Fmap поверх списка, содержащего отдельные элементы и списки - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть такая структура данных

data ShoppingList a
  = Empty
  | Item a 
  | Listofitems [ShoppingList a]
  deriving (Show)

Я пытаюсь написать fmap для этого

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])

Это то, что я написал до сих пор, но оно не компилируется,Можете ли вы помочь мне понять, в чем проблема, объяснение было бы здорово.Две ошибки, которые я получаю

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])
   |                                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

В основном, если у меня есть список = [Item Apple, Empty, [Item Banana, Empty]] Я хочу, чтобы список fmap (++ M) возвращал [Item AppleM.Empty. [Item BananaM, Empty]]

1 Ответ

0 голосов
/ 21 февраля 2019

Примечание к типу данных

Прежде всего, ваш тип данных чрезмерно усложняется.Список элементов действительно должен быть списком, так что вы можете определить data ShoppingList' a = ShoppingList' [a], так как вы в любом случае используете списки.Нет необходимости в том, чтобы список покупок был вложенным.

Решение вашего вопроса

Если, однако, вам это нужно, это решение.Примечание. Я предположил, что вам не нужен список ShoppingLists, так как в вашем определении данных уже есть список.Таким образом, вы можете позвонить

--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]]

Примечание:

  • Вам нужны кавычки вокруг ваших строк,
  • Вам нужно вызвать его на Listofitems

Также помните, что операции добавления строк не эффективны с длинными строками, если вам нужна производительность

...