如何使元组成为Haskell中此类的实例?

问题描述 投票:7回答:2

我一直在读书“ 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)’
haskell types typeclass type-kinds
2个回答
10
投票

好问题。

该类适用于函子类型本身,在您的情况下,函子类型为(,)。要了解它,请注意此处的区别。

: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]

4
投票

(x,y)已经是一个具体的元组类型,包含两个具体的(尽管未知)类型xy。同时,函子或bifunctor应该是parametric

© www.soinside.com 2019 - 2024. All rights reserved.