我一直在读"我希望我在学习Haskell的时候知道“一书,我停止了这个例子:
class Bifunctor p where
bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
first :: (a -> b) -> p a c -> p b c
second :: (b -> c) -> p a b -> p a c我的问题是:如何创建该类的实例?这样做的目的是将函数调用为:
λ bimap (+1) (+2) (8, 9) -- (9, 11)
λ first (*4) (10, 8) -- (40, 8)
λ second (*2) (3, 5) -- (3, 10)我最接近完成这一目标的是:
instance Bifunctor (x, y) where
bimap func func' (x, y) = (func x, func' y)
first func (x, y) = (func x, y)
second func (x, y) = (x, func y)但是它不起作用,它引发了一个错误:
• Expecting two fewer arguments to ‘(x, y)’
Expected kind ‘* -> * -> *’, but ‘(x, y)’ has kind ‘*’
• In the first argument of ‘Bifunctor’, namely ‘(x, y)’
In the instance declaration for ‘Bifunctor (x, y)’发布于 2020-06-08 09:03:49
问得好。
类应用于函子类型本身,在您的例子中,函子类型是(,)。为了得到它的感觉,请注意这里的区别。
:t (,)
(,) :: a -> b -> (a, b)
:t (True,False)
(True,False) :: (Bool, Bool)如果您使用这样的一对类型,可能会更直观:
data Pair a b = Pair a b因为读取类定义会使'p‘的类型应用更加明显。
正如上面所示,Haskell使用类型来表示值,它也使用类型(也用于编译时逻辑),这些类型被命名为种类。
:k Pair
Pair :: * -> * -> *
:k (,)
(,) :: * -> * -> *
:k (Bool,Bool)
(Bool,Bool) :: *
:k Bifunctor
Bifunctor :: (* -> * -> *) -> Constraint这最后一行说明了双函子类是为类型(* -> * -> *)而设计的,而不是(a,b)的种类(*),因此您从GHC获得了错误消息。
您的定义几乎是正确的,以下是正确的定义:
instance Bifunctor (,) where
bimap func func' (x, y) = (func x, func' y)
first func (x, y) = (func x, y)
second func (x, y) = (x, func y)编辑:种类的插图,由@leftroundabout建议
发布于 2020-06-08 09:00:14
(x,y)已经是一个具体的元组类型,包含两种具体(尽管未知)类型x和y。同时,函子或双函子应该是参数的,即在元组实例中,您希望将包含的类型保留为参数,然后在使用这些方法时填充各种不同的具体类型。
也就是说,你基本上想要一个类型级别的lambda。
instance Bifunctor (\x y -> (x, y)) where好吧,Haskell没有类型级别的lambda,但是它在类型级别有部分应用--在这种情况下,甚至不部分,您根本不想将元组构造函数应用于任何类型,而只是让它们处于打开状态。这是这样写的:
instance Bifunctor (,) where如果您只想将其应用于一个参数,则需要编写
instance Functor ((,) a) where如果被解析为Functor (a,),我觉得更容易理解--但这在Haskell实际上是不合法的。
https://stackoverflow.com/questions/62258311
复制相似问题