了解功能类型

时间:2019-05-30 18:57:10

标签: function haskell types functional-programming semantics

我试图理解功能的类型并能够对其进行解释。

两个功能:

insert :: t -> Bool -> ([t],[t]) -> ([t],[t])
insert a True (b,c) = (a:b,c)
insert a False (b,c) = (b,a:c)

partition :: (t -> Bool) -> [t] -> ([t],[t])
partition p [] = ([],[])
partition p (x : xs) = insert x (p x) (partition p xs)

据我所知,我认为该插入功能:

  • insert的类型为t,它接受两个参数bool和两个类型为t的两个列表的元组之一,并返回两个类型为t的列表的元组。

    < / li>
  • partition是类型为t的元组,它返回一个布尔值,它以类型为​​t的列表作为参数,并返回两个类型为t的列表的元组。

是正确的思考方式还是我弄错了?我一直在关注一些教程,这是到目前为止我所做的。

3 个答案:

答案 0 :(得分:10)

  

insert的类型为t,它接受​​两个参数Bool和一个t类型的两个列表的元组之一,并返回两个列表的元组类型t

。首先,重要的是要注意,在Haskell中,每个函数都精确地 一个参数。确实

insert :: t -> Bool -> ([t],[t]) -> ([t],[t])

是以下内容的简短形式:

insert :: t -> (Bool -> (([t],[t]) -> ([t],[t])))

实际上,上面的内容还不是很详细,规范形式为:

insert :: ((->) t) (((->) Bool) (((->) ((,) ([] t)) ([] t))  ((,) ([] t)) ([] t)))

但是上面的内容当然不是很可读,因此让我们坚持第二种形式。

Haskell中的每个函数仅使用一个参数。这里发生的是将参数应用于某个函数的结果会生成一个新函数。

因此,如果我们要生成表达式insert x,则我们构造了类型为Bool -> (([t], [t]) -> ([t], [t]))的函数。

非正式地,有时确实有人说“ 函数需要n个参数”。但是记住这一点很重要。

其次,您忘记了t。我们可以非正式地说insert接受三个参数,一个t类型的值,一个布尔值(Bool类型)和一个带有两个列表的2元组的t个。它将返回一个包含t的两个列表的2元组。根据{{​​1}}是Bool还是True的不同,它会给两个列表之一添加给定值。

例如:

False
  

Prelude> insert 5 False ([], []) ([],[5]) Prelude> insert 5 False ([1,4], [2,5]) ([1,4],[5,2,5]) Prelude> insert 5 True ([1,4], [2,5]) ([5,1,4],[2,5]) Prelude> insert 3 True ([1,4], [2,5]) ([3,1,4],[2,5]) Prelude> insert 3 False ([1,4], [2,5]) ([1,4],[3,2,5]) 是类型partition的元组,它返回t,它接受​​类型bool的列表作为参数,并返回两个列表的元组输入t

否,此处的参数具有类型为t功能。确实,在Haskell中,您可以将函数作为参数传递。

我们可以说(t -> Bool)带有一个“ 谓词”(一个将值映射到partition的函数)和一个Bool的列表,并返回一个包含两个t列表的2元组。根据谓词是否保留列表中的值,这些值将在2元组的第一个或第二个列表中排序。

例如:

t

答案 1 :(得分:6)

否,类型完全相同:

insert的类型为t -> Bool -> ([t], [t]) -> ([t], [t]),这意味着它是一个将类型为t的值作为参数并返回类型为Bool -> ([t], [t]) -> ([t], [t])的函数。非正式地,您可以将insert视为一个带有3个参数的函数:一个类型为t,一个类型为Bool和一个类型为([t], [t]),并返回另一个类型([t], [t])的值。

partition是一个以另一个函数(类型为t -> Bool)作为参数的函数,并返回类型为[t] -> ([t],[t])的函数。再次非正式地,您可以将partition视为接受两个参数(类型为t -> Bool和类型[t])并返回类型为([t], [t])的值。

->本身是类型级别的运算符;它以两种类型作为参数并返回函数类型。它是右关联的,这意味着a -> (b -> c)a -> b -> c是等效的。

答案 2 :(得分:5)

否,insert函数,因此不能为“ t类型”。如果类型为t,则它将是 value

a :: Int
a = 5

a类型的 Int

从函数实现中可以看到,insert接受三个参数:

insert a True (b,c) = ...

参数为aTrue(b, c)

因此,insert的类型恰好是t -> Bool -> ([t],[t]) -> ([t],[t])

  1. 这是一个函数(由于->个原因
  2. 类型为t参数的
  3. ...
  4. ...并返回类型为Bool -> ([t],[t]) -> ([t],[t])另一个函数
    1. ...,它采用类型为Bool(仅Bool)的一个参数
    2. ...并返回函数([t],[t]) -> ([t],[t])
    3. (这应该是更深层次的缩进)... ...带有一个([t],[t])类型的参数(两个列表的元组,每个列表包含 some 类型的值{ {1}})
    4. ...并最终返回类型为t
    5. value

现在,这看起来像是一团糟:函数返回其他函数,这些函数返回函数...但这可以简化。您可以将([t],[t])视为三个参数的函数:

  1. insert是一个疯狂的函数,它返回其他函数:键入insert
  2. t -> Bool -> ([t],[t]) -> ([t],[t])的类型为insert 2
  3. Bool -> ([t],[t]) -> ([t],[t]),如果类型为insert 2 True
  4. ([t],[t]) -> ([t],[t])的类型为insert 2 True ([1], [2])

BOOM!最后一次调用实际上返回了一个值,而不是一个函数!因此,可以将([t],[t])视为三个参数的函数。这个东西叫做currying,它以Haskell被命名的那个人的名字命名-Haskell Curry。