簡體   English   中英

我自己的數據類型的應用函子(Haskell)

[英]Applicative functors for my own data type (Haskell)

我試圖理解haskell,但我遇到了“無法構造無限類型”的錯誤

我想為自己的數據類型實現“<*>”,模仿列表的行為。

到目前為止我的功能代碼:

data List a = Nil | Cons a (List a) deriving Show

instance Functor (List) where
--  fmap :: (Functor f) => (a -> b) -> f a -> f b
    fmap f Nil = Nil
    fmap f (Cons a (b)) = Cons (f a) (fmap f b)

現在我正在嘗試創建一個“應用列表”的實例:

instance Applicative List where
    pure a = Cons a (Nil)
--  (<*>) :: f (a -> b) -> f a -> f b
    (Cons a (b)) <*> (Cons c (d)) = Cons (fmap a (Cons c (d))) (b <*> (Cons c (d)))
    (Nil) <*> _ = Nil
    _ <*> (Nil) = Nil

目標是定義“<*>”,以便模擬列表的行為。 例子:

 (fmap (*)) [5,6,3] <*> [0,2]
--> [0,10,0,12,0,6]

所以它應該創建:

(fmap (*)) (Cons 5 (Cons 6 (Cons 3 (Nil)))) <*> (Cons 0 (Cons 2 (Nil)))
--> (Cons 0 (Cons 10 (Cons 0 (Cons 12 (Cons 0 (Cons 6 (Nil))))))))

但不幸的是,我得到了一個(對我來說)非常無用的錯誤:

10-3.hs:14:65: error:
    * Occurs check: cannot construct the infinite type: b ~ List b
      Expected type: List (List b)
        Actual type: List b
    * In the second argument of `Cons', namely `(b <*> (Cons c (d)))'
      In the expression: Cons (fmap a (Cons c (d))) (b <*> (Cons c (d)))
      In an equation for `<*>':
          (Cons a (b)) <*> (Cons c (d))
            = Cons (fmap a (Cons c (d))) (b <*> (Cons c (d)))
    * Relevant bindings include
        b :: List (a -> b) (bound at 10-3.hs:14:14)
        a :: a -> b (bound at 10-3.hs:14:11)
        (<*>) :: List (a -> b) -> List a -> List b (bound at 10-3.hs:14:18)
   |
14 |     (Cons a (b)) <*> (Cons c (d)) = Cons (fmap a (Cons c (d))) (b <*> (Cons c (d)))
   |                                                                 ^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

我無法弄清楚為什么需要一個列表列表(List (List b)),因為我的數據類型的定義清楚地表明需要一個普通列表作為 Cons 的第二個參數。

我希望有人可以幫助我!

編輯:謝謝你解決了它。 現在這可能是題外話,但我試圖復制用於列表的原始語法來解決它。 它在 Prelude 包中定義如下:

instance Applicative [] where
    {-# INLINE (<*>) #-}
    fs <*> xs = [f x | f <- fs, x <- xs]

因為我不能使用列表理解,所以我不想創建一個實際的列表(我以后可以轉換它,但我不喜歡這個想法)。 我用 lambdaBot 翻譯了語法糖並得到了這個:

fs <*> xs = concatMap (\ f -> concatMap (\ x -> [f x]) xs) fs

有沒有辦法做到這一點,或者這本質上是否等同於使用附加(助手)功能?

在違規行中:

  (Cons a (b)) <*> (Cons c (d)) = Cons (fmap a (Cons c (d))) (b <*> (Cons c (d)))

子表達式fmap a (Cons c (d))的類型為List b ,而您試圖將其Cons(b <*> (Cons c (d)))上,它也具有List b的類型。 但請記住,類型是Cons :: a -> List a -> List a 注意Cons的第一個元素需要是一個元素,第二個元素應該是一個列表。 因此,編譯器假定您的元素類型本身是List b ,然后它報告它期望第二個參數的類型為List (List b)

要解決此問題,您應該編寫一個append :: List a -> List a -> List a function 並使用它,而不是使用Cons

  (Cons a (b)) <*> (Cons c (d)) = append (fmap a (Cons c (d))) (b <*> (Cons c (d)))

關於語法的小提示:您可以像這樣使代碼更簡潔:

  Cons f fs <*> xs = append (fmap f xs) (fs <*> xs)

提示:

  • 使用f之類的暗示性名稱來表示函數,並在末尾添加一個s來表示某些東西的列表。
  • 避免冗余模式匹配(Cons c (d)) -> xs
  • 避免多余的括號。 特別是,您永遠不必在(b)(d)等變量周圍寫括號。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM