多参数函数的Haskell类型声明

时间:2016-04-28 12:19:17

标签: haskell

我正在浏览Haskell的this简介,其中包含以下示例:

data Tree a             = Leaf a | Branch (Tree a) (Tree a) 

它说的基本上也是定义类型:

Branch                  :: Tree a -> Tree a -> Tree a
Leaf                    :: a -> Tree a

我理解Leaf的定义是说它将a映射到Tree a。但我不理解分支定义,我将其视为" Tree a Tree a Tree分支到a } .icon这听起来不正确。这是因为默认情况下所有Haskell函数都被调用了吗?

3 个答案:

答案 0 :(得分:4)

没有。如果它有如下签名:

Branch :: (Tree a, Tree a) -> Tree a

然后你应该给它一个元组,并调用构造函数,如:

Branch (tree1,tree2)

Branch有签名:

Branch :: Tree a -> Tree a -> Tree a

或使用明确的括号:

Branch :: Tree a -> (Tree a -> Tree a)

因此,当您向Branch提供第一个参数(例如Branch tree1)时,签名为:

(Branch t1) :: Tree a -> Tree a

当您最终输入第二个参数t2时,其类型将折叠为:

((Branch t1) t2) :: Tree a

更方便的例子是例如(+),它不是构造函数,而是函数。 (+) 我们的(+)有签名

(+) :: Int -> Int -> Int

(Haskells plus更通用,但现在不要考虑这个。)

如果你现在写(5+),你已经将你的功能专门用于一个功能:

(5+) :: Int -> Int

换句话说,您构建了一个 new 函数,该函数会将5添加到给定数字。

由于(a,b) -> ca -> b -> c的签名有点等同,因此Haskell提供了curryuncurry函数:

curry :: ((a, b) -> c) -> a -> b -> c
uncurry :: (a -> b -> c) -> ((a, b) -> c)

如果你决定需要一个额外的Branch构造函数来构造一个元组,你可以构造这样的构造函数:

branchTuple :: (Tree a, Tree a) -> Tree a
branchTuple = uncurry Branch

答案 1 :(得分:2)

Branch (Tree a) (Tree a)是一个带有两个类型参数的构造函数,两个参数都是Tree a,构造函数的结果是Tree a,因此

的定义
Tree a -> Tree a -> Tree a
  

我理解Leaf的定义是说它将a映射到a的树。但我不明白分支定义,不应该是这样的:

Branch :: (Tree a, Tree a) -> Tree a

不,因为如果您使用(Tree a, Tree a),那么您将定义一个单元类型参数,它是一个元组。

答案 2 :(得分:2)

  

我把它读作“分支映射树的树到树的树”

您可以将定义视为一个函数,它接受Tree a并返回另一个函数,该函数也需要Tree a并生成Tree a(这是最终结果,有两个分支的树)。您Branch的签名等同于

Branch :: Tree a -> (Tree a -> Tree a)

每个函数只有一个输入参数的概念称为currying