Segementing a recursive tree in haskell Could somebody help me work out how to abstract the recursion from this code for me please?
I'm trying to write something that takes a pandoc structure, and subdivides the tree
whenever it finds a sentence, so:

&lt;span&gt;This sentence. Should split.&lt;/span&gt;


becomes:

&lt;span&gt;
  &lt;span { sentence }&gt;This sentence.&lt;/span&gt;
  &lt;span { sentence }&gt; Should split.&lt;/span&gt;
&lt;/span&gt;


I have a working implementation, but the recursive part is a bit repetitive:

segment :: [Inline] -&gt; [Inline]
segment [] = []
segment [el] = [el]
segment els @ (head:tail) =
  case head of
    Emph ch -&gt; map (Emph . toList) (segment ch) ++ segment tail
    Strong ch -&gt; map (Strong . toList) (segment ch) ++ segment tail
    Strikeout ch -&gt; map (Strikeout . toList) (segment ch) ++ segment tail
    Superscript ch -&gt; map (Superscript . toList) (segment ch) ++ segment tail
    Subscript ch -&gt; map (Subscript . toList) (segment ch) ++ segment tail
    SmallCaps ch -&gt; map (SmallCaps. toList) (segment ch) ++ segment tail
    Quoted qt ch -&gt; map (Quoted qt . toList) (segment ch) ++ segment tail
    Cite cs ch -&gt; map (Cite cs . toList) (segment ch) ++ segment tail
    Span attr ch -&gt; map (Span attr . toList) (segment ch) ++ segment tail
    _ -&gt;
      maybe [sentence els] (\i -&gt; (sentence $ take i els) : segment (drop i els))
        $ (1 +) &lt;$&gt; List.findIndex split els
  where
    sentence = Span ("sentence", [], [])

split :: Inline -&gt; Bool
split (Str str) = endsWith "." str || endsWith "?" str || endsWith "!" str
split _         = False

endsWith :: String -&gt; String -&gt; Bool
endsWith suff str = suff `List.isSuffixOf` str

toList :: a -&gt; [a]
toList = (: [])


I'm trying to work out a way to hand in some f that will model the part that splits the structure
(i.e the bottom bit), but I'm struggling as the function has to be [Inline] -&gt; [Inline], it's also
as if it needs to be Inline -&gt; [Inline] -&gt; [Inline] as each of the recursive steps need the original
constructor in order to preserve the structure of the document, ie:

&lt;span&gt;&lt;strong&gt;This sentence. Should split.&lt;/strong&gt;&lt;/span&gt;


becomes:

&lt;span&gt;
  &lt;strong&gt;&lt;span { sentence }&gt;This sentence.&lt;/span&gt;&lt;/strong&gt;
  &lt;strong&gt;&lt;span { sentence }&gt; Should split.&lt;/span&gt;&lt;/strong&gt;
&lt;/span&gt;
I'll start with something unrelated to recursion: A first cleanup step might be to reduce the repetition in segment:

segment els @ (head:tail) =
  let constr = case head of
                 Emph ch        -&gt; Just (Emph, ch)
                 Strong ch      -&gt; Just (Strong, ch)
                 Strikeout ch   -&gt; Just (Strikeout, ch)
                 Superscript ch -&gt; Just (Superscript, ch)
                 Subscript ch   -&gt; Just (Subscript, ch)
                 SmallCaps ch   -&gt; Just (SmallCaps, ch)
                 Quoted qt ch   -&gt; Just (Quoted qt, ch)
                 Cite cs ch     -&gt; Just (Cite cs, ch)
                 Span attr ch   -&gt; Just (Span attr, ch)
                 _              -&gt; Nothing
      sentence = Span ("", ["sentence"], [])
  in case constr of
    Just (inlnConstr, ch) -&gt; map inlnConstr (segment ch) ++ segment tail
    _               -&gt;
      maybe [sentence els] (\i -&gt; (sentence $ take i els) : segment (drop i els))
        $ (1 +) &lt;$&gt; List.findIndex split els


Note that we not only cut away the repeating (segment ch) and ++ segment tail, but also the toList, which is just an id here (as the result of segment already is a List.

Next would be the splitting, which could be done using break instead of findIndex, drop, and take:

      case break split els of
        (_, [])    -&gt; [sentence els]
        (xs, y:ys) -&gt; sentence (xs ++ [y]) : segment ys


The last part of your post might better be asked on stackoverflow, as there is no working code for this yet.