Home > Software design >  How to do recursion for recursive data type in function in Haskell
How to do recursion for recursive data type in function in Haskell

Time:11-30

I am trying to implement menu function that returns all titles from custom data type Page

data Page = Text String
         | Title String [Page] deriving(Show)
menu :: Page -> [String]
menu (Text a) = []
menu (Title name content ) = [name]

But I want also this function will work also for some "hierarchy" of pages, for example, like in index :

index = Title "Home" [
  Title "Welcome!"[
    Text "Hello World!", 
    Title "Lorem"[Text "ipsum"]],
  Title "dolor"[
    Title "no title" [Text "Haskell"],
    Title "Look!" [Text "test"]],
  Title "Finish" [Text "It will be look great"]]

I done some functions for this, but I have no idea how to start recursion for "hierarchy" Page

menu :: Page -> [String]
menu (Text a) = []
menu (Title name content ) = [name]

The output is

*Main> menu index
["Home"]

But can I do list of all Title in index ?

Thanks a lot in advance for answer!

CodePudding user response:

One way to do it is as follows:

data Page = Text String
         | Title String [Page] deriving(Show)
menu :: Page -> [String]
menu (Text a) = [a]
menu (Title name content) = name : concatMap menu content

data Page = Text String
         | Title String [Page] deriving(Show)
menu :: Page -> [String]
menu (Text a) = [a]
menu (Title name content) = name : concatMap menu content

A small test:

λ> menu index
["Home","Welcome!","Hello World!","Lorem","ipsum","dolor","no title","Haskell","Look!","test","Finish","It will be look great"]

We are using concatMap.

Since Text a is a leaf, we return the extracted a which is its String in a list as [a].

Title name content has 2 parts. name is just a string, so we add it to the list and recursively call menu. But we can't just map menu over content, since content is a list of Pages. That means that we have a list of recursive data types. So we use concatMap that just concatenates the lists that are produced by each Page in the list.

If you like to keep track of whether a string was a Title or a Text:

data Page = Text String
         | Title String [Page] deriving(Show)
menu :: Page -> [String]
menu (Text a) = ["Text "    a]
menu (Title name content) = ("Title "    name) : concatMap menu content
  • Related