Haskell的《 Haskell从第一原理编程》一书中有一个练习,要求我在数据类型Applicative
上实例化List
:
data List a =
Nil
| Cons a (List a)
deriving (Eq, Show)
instance Functor List where
fmap _ Nil = Nil
fmap f (Cons x xs) = Cons (f x) (fmap f xs)
instance Applicative List where
pure x = Cons x Nil
Nil <*> _ = Nil
_ <*> Nil = Nil
Cons f fs <*> Cons x xs = Cons (f x) ((fmap f xs) <> (fs <*> xs))
我编写了以上代码,发现必须首先实例Semigroup
才能使<>
运算符起作用。
可以在没有实例Semigroup
的情况下实现吗?
答案 0 :(得分:2)
是。您在此处在定义中使用>>> class Foo(int):
__slots__ = ()
def __new__(cls, a, b, c, add=True):
value = cls.sum(a, b, c) if add else cls.subtract(a, b, c)
return super().__new__(cls, value)
@staticmethod
def sum(a, b, c):
return a + b + c
@staticmethod
def subtract(a, b, c):
return c - b - a
>>> foo = Foo(1, 2, 3, True)
>>> foo
6
>>> type(foo)
<class '__main__.Foo'>
函数:
(<>)
因此您可以将其替换为对另一个函数的调用:
instance Applicative List where
pure x = Cons x Nil
Nil <*> _ = Nil
_ <*> Nil = Nil
Cons f fs <*> Cons x xs = Cons (f x) ((fmap f xs) <> (fs <*> xs))
-- ^ call to the (<>) function
但是请注意,在这里您可能实现的功能与您在此处打算实现的功能不同。在这里,您实现了一个针对两个列表instance Applicative List where
pure x = Cons x Nil
Nil <*> _ = Nil
_ <*> Nil = Nil
Cons f fs <*> Cons x xs = Cons (f x) (append (fmap f xs) (fs <*> xs))
where append = ...
和[f1, f2, f3]
的函数,该函数将使用[x1, x2, x3, x4]
和fs
的矩阵的“上三角”来计算一个列表,因此结果为xs
。请注意,这里缺少[f1 x1, f1 x2, f1 x3, f1 x4, f2 x2, f2 x3, f2 x4, f3 x3, f3 x4]
,f2 x1
和f3 x1
。
答案 1 :(得分:0)
好吧,您使用了一种叫做<>
的东西,Haskell知道,这件事(特别是您导入的<>
的定义是因为您在任何地方都没有定义运算符)需要一个半组。解决方案是使用其他名称或在本地定义它:
Cons f fs <*> xs = (f <$> xs) <> (fs <*> xs)
where xs <> Nil = xs
Nil <> xs = xs
Cons x xs <> ys = Cons x (xs <> ys)