0

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]
2
  • Welcome to Stack Overflow. Please take the tour to learn how Stack Overflow works and read How to Ask on how to improve the quality of your question. Then edit your question to include your source code as a working minimal reproducible example, which can be tested by others. As it stands you forgot to add your code, just a function signature isn't gonna cut it. Commented Nov 25, 2022 at 12:12
  • The sentence 'chapter names that do not contain text blocks (Text) in their type list [Article]' is not correct. There is no such thing as a type List, all elements in a Haskell list are of the same type, which is Article in your case. Commented Nov 25, 2022 at 14:34

1 Answer 1

2

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!

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.