Home > Net >  Haskell-Custom data types
Haskell-Custom data types

Time:11-25

I need some advice on how to return a list of chapter names that do not contain text blocks (Text) in their type list [Article]

data Article = Text String
             | Section String [Article] deriving (Show)

myArticle :: Article
myArticle = Section "Document" [
                 Section "Introduction" [
                       Text "My intoduction",
                       Section "Notation" [Text "alpha beta gamma"]],
                 Section "Methods" [
                       Section "Functional Programming" [Text "FPR"],
                       Section "Logical Programming" [Text "LPR"]],
                 Section "Results" [Text "All is great"]]
names :: Article -> [String]

Expected output:

names myArticle = ["Document", "Methods"]

I tried the basic functions:

names :: Article -> [String]

CodePudding user response:

Always start by observing the structure of your datatype:

                     Section
                   /        \
                Text        Section
                            /   |  \
                         Text Text  Text

You can see that this is a tree. Thus we start by deconstructing this tree in names:

names :: Article -> [String]
names a = case a of
  Text _ -> []
  Section chptr xs -> []

We only want to return chptr if none of it's childs in the listxs is text. Thus we need a function to know whether something is text:

isText :: Article -> Bool
isText (Text _) = True
isText _ = False

Now looking at names we can use the built-in any :: (a -> Bool) -> [a] -> Bool function to return chptr, if none of it's childs is text:

names :: Article -> [String]
names a = case a of
  Text _ -> []
  Section chptr xs -> 
    (if any isText xs then [] else [chptr]) 

But names only returns the first chapter name. We already concluded this is a tree, and processing these in Haskell is usually done recursively. So we must call names again on our list xs of sections, and add the result to the names we already found:

names :: Article -> [String]
names a = case a of
  Text _ -> []
  Section chptr xs -> 
    (if any isText xs then [] else [chptr])    concatMap names xs 

voila!

  • Related