我一直在阅读《 What I wish I knew when learning 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)’
最佳答案
好问题。
该类适用于函子类型本身,在您的情况下,函子类型为(,)。要了解它,请注意此处的区别。
:t (,)
(,) :: a -> b -> (a, b)
:t (True,False)
(True,False) :: (Bool, Bool)
如果您使用了Pair类型,可能会更直观:
data Pair a b = Pair a b
因为阅读类定义会使'p'的类型应用更加明显。
就像Haskell将类型用作值一样,如上所述,它也将类型用于类型(也用于编译时逻辑),这些类型称为Kinds。
:k Pair
Pair :: * -> * -> *
:k (,)
(,) :: * -> * -> *
:k (Bool,Bool)
(Bool,Bool) :: *
:k Bifunctor
Bifunctor :: (* -> * -> *) -> Constraint
最后一行说明Bifunctor类是为
(* -> * -> *)
类型而不是(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 建议的种类说明