6

我试图定义这个函数来重新组合三个对列表:

{-# LANGUAGE RankNTypes #-}

mapAndZip3 :: (forall x. x -> f x) -> [a] -> [b] -> [c] 
                                   -> [(f a, f b, f c)]
mapAndZip3 f la lb lc = zipWith3 (\a b c -> (f a, f b, f c)) la lb lc


main = do
    let x = mapAndZip3 (fst) [(1,"fruit"), (2,"martini")] 
                             [("chips","fish"),("rice","steak")]
                             [(5,"cake"),(4,"pudding")]
    print x -- was expecting [(1,"chips",5), (2,"rice",4)]

起初我没有包括RankNTypesor forall,但后来看到this,即liftTup定义后,我认为它应该足够了。

但显然,它不是,因为我仍然得到一个错误:

mapAndZip3.hs:8:25:
Couldn't match type `x' with `(f0 x, b0)'
  `x' is a rigid type variable bound by
      a type expected by the context: x -> f0 x at mapAndZip3.hs:8:13
Expected type: x -> f0 x
  Actual type: (f0 x, b0) -> f0 x
In the first argument of `mapAndZip3', namely `(fst)'

我显然对forall关键字的理解有限,但据我所知,在这种情况下,它应该允许f接受任何类型。我不明白的是:一旦在给定的上下文中使用一次,定义是否会在剩余的上下文中得到“固定”?

似乎不是这样,因为如果我用 Ints 替换“chips”和“rice”,编译器仍然会抱怨,所以我想我假设有问题(当然,如果我mapAndZip3在后一种情况下删除了类型注释,一切正常,因为签名被简化为 mapAndZip3 :: (a -> t) -> [a] -> [a] -> [a] -> [(t, t, t)],但这不是我想要的)。

我也发现了这个问题,但不能确定这是否是同一个问题,因为我试图应用的函数不是id,而是fstsnd实际上返回不同类型的函数(a -> b)

4

2 回答 2

8

The problem is that fst doesn't have the required type

(forall x. x -> f x)

The type of fst is

fst :: (a, b) -> a

and a is not of the form f (a,b). The f there is a variable that must be instantiated with a type constructor, something like [], Maybe, Either Bool. f can't stand for any "type function" like Λ (a,b) -> a, it must be a type constructor.

It works if we provide it a function of the required type (sorry, stupid example):

{-# LANGUAGE RankNTypes #-}

mapAndZip3 :: (forall x. x -> f x) -> [a] -> [b] -> [c]
                                   -> [(f a, f b, f c)]
mapAndZip3 f la lb lc = zipWith3 (\a b c -> (f a, f b, f c)) la lb lc

fst0 x = (True,x)

main = do
    let x = mapAndZip3 (fst0) [(1 :: Int,"fruit"), (2,"martini")]
                             [("chips","fish"),("rice","steak")]
                             [(5 :: Int,"cake"),(4,"pudding")]
    print x

since here fst0 has the type a -> ((,) Bool) a, which has the form x -> f x.

于 2013-06-05T10:39:37.807 回答
6
于 2013-06-05T10:38:51.447 回答