I have a data structure like so
data ShoppingList a
= Empty
| Item a
| Listofitems [ShoppingList a]
deriving (Show)
I am trying to write the fmap for this
instance Functor ShoppingList where
fmap f Empty = Empty
fmap f (Item i) = Item (f i)
fmap f (Listofitems [Empty]) = Empty
fmap f (Listofitems ((Item a):Listofitems [as])) = Listofitems $ (fmap f (Item a)) (fmap f Listofitems [as])
This is what I wrote so far ,but its not compiling ,can you please help me understand what the problem here is , an explanation would be awesome . The two errors that I am getting
src\Ml.hs:19:33: error:
* Couldn't match expected type `[ShoppingList a]'
with actual type `ShoppingList a0'
* In the pattern: Listofitems [as]
In the pattern: (Item a) : Listofitems [as]
In the pattern: Listofitems ((Item a) : Listofitems [as])
* Relevant bindings include
a :: a (bound at src\Ml.hs:19:30)
f :: a -> b (bound at src\Ml.hs:19:8)
fmap :: (a -> b) -> ShoppingList a -> ShoppingList b
(bound at src\Ml.hs:16:3)
|
19 | fmap f (Listofitems ((Item a):Listofitems [as])) = Listofitems $ (fmap f (Item a)) (fmap f Listofitems [as])
| ^^^^^^^^^^^^^^^^
src\Ml.hs:19:68: error:
* Couldn't match expected type `b -> [ShoppingList b]'
with actual type `ShoppingList b'
* The function `fmap' is applied to three arguments,
but its type `(a -> b) -> ShoppingList a -> ShoppingList b'
has only two
In the second argument of `($)', namely
`(fmap f (Item a)) (fmap f Listofitems [as])'
In the expression:
Listofitems $ (fmap f (Item a)) (fmap f Listofitems [as])
* Relevant bindings include
f :: a -> b (bound at src\Ml.hs:19:8)
fmap :: (a -> b) -> ShoppingList a -> ShoppingList b
(bound at src\Ml.hs:16:3)
|
19 | fmap f (Listofitems ((Item a):Listofitems [as])) = Listofitems $ (fmap f (Item a)) (fmap f Listofitems [as])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Basically if I have a list = [ Item Apple ,Empty , [Item Banana ,Empty ] ] I want fmap (++ M )list to return [Item AppleM .Empty .[Item BananaM ,Empty]]
First of all, your data type is overly complicates. A list of items should indeed be a list, so you can should define data ShoppingList' a = ShoppingList' [a]
as you are using lists in yours anyways. There is no need a Shopping List should be nested.
If, however, you need it that way, this is a solution. Note I assumed you did not need a list of ShoppingLists, as your data definition already has a list in it. So you can call
--fmap :: (a -> b) -> ShoppingList a -> ShoppingList b
fmap _ Empty = Empty
fmap f (Item i) = Item (f i)
fmap f (Listofitems ls) = Listofitems $ map (fmap f) ls
>>fmap (++ "M") $ Listofitems [Item "Apple", Empty, Listofitems [Item "Banana", Empty]]
Listofitems [Item "AppleM",Empty,Listofitems [Item "BananaM",Empty]]
Note:
Also remember the String append operations is not efficient with long strings in case you need performance