为什么Haskell类型的签名声明有多个箭头?

时间:2013-12-08 22:27:39

标签: haskell syntax types

对不起,措辞很差,但很难描述。

我想我会跳到这个例子:

add                     :: Integer -> Integer -> Integer
add x y                 =  x + y

为什么:

:: Integer -> Integer -> Integer

而不是:

:: Integer, Integer -> Integer

箭头是“Function type-mapping operator”,而不是某种分隔符,不是吗?

3 个答案:

答案 0 :(得分:21)

因为蜷缩。想想这个的类型:

add 3 :: Integer -> Integer

如果你给add一个数字,它会返回一个将Integer映射到另一个整数的函数。所以你可以这样做:

map (add 3) [1..10]

以与部分应用的返回类型不同的方式处理参数是没有意义的。

编辑以澄清

我认为bheklilr非常重视类型签名可以像这样读取

add :: Integer -> (Integer -> Integer)

我们可以使用一个带有更多参数的函数zipWith3,因为它是我唯一能想到的。

zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]

如果我们只读取它的作用,它需要一个函数,它接受3个值并分别返回第四个然后返回3个值的列表,并返回第四个值的列表。尝试一下。

add3 :: Int -> Int -> Int -> Int
add3 a b c = a + b + c

Prelude>zipWith3 add3 [1] [2] [3]
[6]

虽然在这种情况下所有值都是Int类型,但它仍然证明了这一点。

现在如果我们不给它所有列表怎么办?如果我们没有列出add3列表,那该怎么办?

zipWith3 add3 :: [Int] -> [Int] -> [Int] -> [Int]
zipWith3 add3 :: [Int] -> ([Int] -> [Int] -> [Int])
zipWith3 add3 :: [Int] -> [Int] -> ([Int] -> [Int])

所以,现在我们有一个函数,它接受3个列表并返回一个列表。但这也是一个函数,它接受一个列表返回一个带有2个列表并返回一个列表的函数。真的无法区分它们。

(zipWith3 add3) [1,2] [3,4] [5,6] :: [Int]
(zipWith3 add3) [1,2] :: [Int] -> [Int] -> [Int]

看看我要去哪里?参数之间没有区别是返回类型。

答案 1 :(得分:16)

我的“啊哈”时刻是我意识到的那一刻

map :: (a -> b) -> [a] -> [b]
明确分组时,

实际上看起来更自然:

map :: ( a -> b )
    -> ([a]->[b])

接受一个函数并返回一个列表函数。如果没有明确的定义,这种分组不太有效,是吗?

map :: ( a -> b
       ,[a])->[b]

然而,这种分组在某种程度上是一种更“深入”,更有用的思考功能的方式。特别是,如果你概括它:

class Functor f where
  fmap :: (a->b) -> f a->f b

functor执行两项操作:采用某种类型(例如ab)并将其与其他类型(f af b相关联) 。但它也需要态射a -> b)并将其与另一个态射(f a -> f b)相关联。

答案 2 :(得分:7)

类型签名更准确地读作

add :: Integer -> (Integer -> Integer)

有很大不同
add :: (Integer -> Integer) -> Integer

第一个表示一个函数,它接受Integer并返回一个新函数,该函数接受Integer并返回Integer。这是为了便于部分应用功能,所以像

这样的东西
(+) :: Int -> Int -> Int  -- specialized to Int

(1 +) :: Int -> Int

> map (1 +) [1..10]
[2,3,4,5,6,7,8,9,10,11]