在Haskell中创建具有多个参数的参数化类型

时间:2018-02-11 22:26:35

标签: haskell

我有以下数据类型:

data HVF a b = HVF { h1 :: !a
                   , l1 :: !Int
                   } deriving (Show, Eq)

instance Monoid (HVF a b) where {...}

我尝试写一个函数:

hvf :: (Num a, Ord a) => Fold a (HVF a b)
hvf = Fold tally summarize
  where
    tally x = HVF x

    summarize (HVF x y) = (HVF x y)

data Fold i o = forall m . Monoid m => Fold (i -> m) (m -> o)

但是我收到了错误:

• Couldn't match type ‘Int -> HVF a b0’ with ‘HVF a b1’
  Expected type: (Int -> HVF a b0) -> HVF a b
    Actual type: HVF a b1 -> HVF a b
• In the second argument of ‘Fold’, namely ‘summarize’
  In the expression: Fold tally summarize
  In an equation for ‘hvf’:
      hvf
        = Fold tally summarize
        where
            tally x = HVF x
            summarize (HVF x y) = (HVF x y)
• Relevant bindings include
    hvf :: Fold a (HVF a b) (bound at src/Data/HVFScanner/HVF.hs:119:1)
    |
119 | hvf = Fold tally summarize
    |  

我不明白,任何人都可以用英语解释吗?

其他信息......

Fold来自https://github.com/Gabriel439/slides/blob/master/munihac/foldmap.md#-in-one-slide

2 个答案:

答案 0 :(得分:3)

Fold有两个值,一个tally函数将输入值注入某个monoid,一个summarize函数从monoid中提取结果。

非正式:

tally :: i -> m
summarize :: m -> o

其中mMonoid

在您的代码中

hvf :: (Num a, Ord a) => Fold a (HVF a b)
hvf = Fold tally summarize
  where
    tally x = HVF x

    summarize (HVF x y) = (HVF x y)

您的tally类型为a -> Int -> HVF a b,其中(因为类型中的->是右关联的)相当于a -> (Int -> HVF a b)。因此,类型检查器假定您的输入类型ia,而您的幺半群类型mInt -> HVF a b

您的summarize类型为HVF a b1 -> HVF a b2。但是,要与Fold tally一起使用,它需要m -> o类型mInt -> HVF a b。这是错误消息抱怨的内容:summarize的参数类型为HVF a b1,但summarize用于需要接受Int -> HVF a b的上下文中

我不理解你的其余代码,但我认为你在HVF忘记了对tally的争论。也许像tally x = HVF x 0

答案 1 :(得分:3)

错误实际上在于tally。那应该是类型a -> m,其中幺半群在这种情况下是HVF a b,即

tally :: a -> HVF a b

但你已经实施了什么

tally x = HVF x

实际上有a -> Int -> HVF a b类型,因为HVF x仍然缺少Int字段,即您只有部分应用HVF值构造函数,由于Haskell在 curried模式中的工作方式,缺少参数会自动延迟为tally函数的额外参数。

有点奇怪的是,这本身就是而不是类型错误:签名a -> Int -> HVF a b实际上形式为a -> m,但是在这种情况下,m是函数类型Int -> HVF a b。实际上,该函数类型也有一个Monoid实例!

但这意味着您还需要类型

summarise :: (Int -> HVF a b) -> HVF a b

...但这不是summarise的类型,只是

summarise :: HVF a b -> HVF a b

因此误导性错误信息。