【问题标题】:Understanding the types of functions了解函数的类型
【发布时间】:2019-10-16 10:56:19
【问题描述】:

我正在尝试理解函数的类型并能够解释它们。

两个功能:

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 类型列表的元组。

  • partition 是一个 t 类型的元组,它返回一个布尔值,它接受一个 t 类型的列表作为它的参数,并返回一个由两个 t 类型的列表组成的元组。

这是正确的思考方式还是我理解错了?我一直在关注一些教程,这是我目前所理解的。

【问题讨论】:

  • 看来你对柯里化的理解太基础了,柯里化是 Haskell 中的一个重要概念。看看Learn You A Haskell
  • insert 不是t 类型,它的第一个参数t 类型。 insert a 如您所描述的,还有两个参数。 --- partition 不是一个元组,它是一个函数。它的第一个参数p 不是一个元组,它是一个函数。

标签: function haskell types functional-programming semantics


【解决方案1】:

不,类型完全如图所示:

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】:

    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 类型)和一个带有两个ts 列表的2 元组。它将返回两个 ts 列表的 2 元组。根据BoolTrue 还是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 类型的列表组成的元组。

    不,这里的参数类型为(t -> Bool),它是一个函数。事实上,在 Haskell 中,您可以将函数作为参数传递。

    非正式地我们可以说partition 接受一个“谓词”(一个将值映射到Bools 的函数)和一个ts 的列表,它返回一个 2-带有两个ts 列表的元组。根据谓词是否适用于列表中的值,这些值在 2 元组的第一个或第二个列表中排序。

    例如:

    Prelude> partition (>3) [1,4,2,5]
    ([4,5],[1,2])
    Prelude> partition (>3) [1,3,0,2]
    ([],[1,3,0,2])
    Prelude> partition (>3) [1,7,8,0]
    ([7,8],[1,0])
    Prelude> partition (>3) [1,7,8,9]
    ([7,8,9],[1])
    

    【讨论】:

      【解决方案3】:

      不,insert 是一个函数,所以它不能是“t 类型”。如果它是t 类型,它将是一个

      a :: Int
      a = 5
      

      这里a类型 Int

      从函数实现中可以看出,insert 采用三个参数:

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

      参数是aTrue(b, c)

      所以,insert 的类型正好是t -> Bool -> ([t],[t]) -> ([t],[t])

      1. 这是一个函数(因为->s)
      2. ...一个参数的一些类型t
      3. ...并返回Bool -> ([t],[t]) -> ([t],[t]) 类型的另一个函数
        1. ...接受Bool 类型的一个参数(仅限Bool
        2. ...并返回一个函数([t],[t]) -> ([t],[t])
        3. (这应该是更深一层的缩进)...它采用([t],[t]) 类型的一个参数(两个列表的元组,每个列表都包含some 类型t 的值)
        4. ...最后返回一个([t],[t])类型的

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

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

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

      【讨论】:

      • 函数也是值。问题不在于t 不是(或不能是)一个函数,而是它没有必须 成为一个函数。例如,id :: t -> t,但id 'c'id (+) 都进行类型检查,因为您可以将tCharNum a => a -> a -> a 统一起来。
      • @chepner,是的,你的措辞更好。我试图区分作为某种数据的值和作为行为的函数,同时也试图不使答案过于复杂,因为人们也可以将函数传递给其他函数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-21
      • 1970-01-01
      • 2014-03-09
      相关资源
      最近更新 更多