简体   繁体   English

我自己的数据类型的应用函子(Haskell)

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

I´m trying to understand haskell and I´m stuck with a "cannot construct the infinite type"-error我试图理解haskell,但我遇到了“无法构造无限类型”的错误

I want to implement "<*>" for my own data type, imitating the behaviour of a list.我想为自己的数据类型实现“<*>”,模仿列表的行为。

My functioning code so far:到目前为止我的功能代码:

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)

Now I´m trying to create an instance of 'Applicative List':现在我正在尝试创建一个“应用列表”的实例:

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

The goal is to define '<*>' so it simulates the behaviour of a List.目标是定义“<*>”,以便模拟列表的行为。 Example:例子:

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

so it should create:所以它应该创建:

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

but unfortunately I get a (to me) pretty unuseful error:但不幸的是,我得到了一个(对我来说)非常无用的错误:

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.

I cant figure out why a List of Lists is expected (List (List b)) because the definition of my data type clearly states a normal List is required as the second parameter for Cons.我无法弄清楚为什么需要一个列表列表(List (List b)),因为我的数据类型的定义清楚地表明需要一个普通列表作为 Cons 的第二个参数。

I hope someone can help me with this!我希望有人可以帮助我!

EDIT: Thank you this solved it.编辑:谢谢你解决了它。 This might be off-topic now, but I was trying to copy the original syntax used for lists to solve it.现在这可能是题外话,但我试图复制用于列表的原始语法来解决它。 Its defined in the Prelude Package as follows:它在 Prelude 包中定义如下:

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

As I couldn´t use the list comprehension, as for me not wanting to create an actual list (shure I could just convert it later on but I dont like that idea).因为我不能使用列表理解,所以我不想创建一个实际的列表(我以后可以转换它,但我不喜欢这个想法)。 I translated the syntactic sugar with lambdaBot and got this:我用 lambdaBot 翻译了语法糖并得到了这个:

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

Is there a way to do it like this or is this essentialy the equivalent to doing it with an append (helper)-function?有没有办法做到这一点,或者这本质上是否等同于使用附加(助手)功能?

In the offending line:在违规行中:

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

The subexpression fmap a (Cons c (d)) has type List b and you are trying to Cons that onto (b <*> (Cons c (d))) which also has type List b .子表达式fmap a (Cons c (d))的类型为List b ,而您试图将其Cons(b <*> (Cons c (d)))上,它也具有List b的类型。 But remember that the type is Cons :: a -> List a -> List a .但请记住,类型是Cons :: a -> List a -> List a Note that the first element of Cons needs to be an element and the second element should be a list.注意Cons的第一个元素需要是一个元素,第二个元素应该是一个列表。 So, the compiler assumes that your element type is itself List b and then it reports that it expects the second argument to have type List (List b) .因此,编译器假定您的元素类型本身是List b ,然后它报告它期望第二个参数的类型为List (List b)

To fix this, instead of using Cons you should write an append :: List a -> List a -> List a function and use that:要解决此问题,您应该编写一个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)))

Small note about syntax: you can make the code quite a bit cleaner like this:关于语法的小提示:您可以像这样使代码更简洁:

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

Tips:提示:

  • Use suggestive names like f for functions, and add an s to the end for lists of something.使用f之类的暗示性名称来表示函数,并在末尾添加一个s来表示某些东西的列表。
  • Avoid redundant pattern matching (Cons c (d)) -> xs .避免冗余模式匹配(Cons c (d)) -> xs
  • Avoid redundant parentheses.避免多余的括号。 In particular you never have to write parentheses around variables like (b) and (d) .特别是,您永远不必在(b)(d)等变量周围写括号。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM