【问题标题】:Understanding Data.Function.on type signature了解 Data.Function.on 类型签名
【发布时间】:2017-07-23 03:42:56
【问题描述】:

当谈到 Haskell 语法和函数式编程语言时,我仍然是初学者,所以当我查看 Data.Function.on 的类型声明 on :: (b -> b -> c) -> (a -> b) -> a -> a -> c 时,我的解释是它需要四个参数:(b -> b -> c)(a -> b)aa,并返回c。但是,当我查看Data.Function.on 的一般使用语法(*) `on` f = \x y -> f x * f y 时,它只采用两个函数参数,而不是四个,那么类型签名与使用语法有何关系?

【问题讨论】:

  • (->) 是右结合的,所以(b -> b -> c) -> (a -> b) -> a -> a -> c 等价于(b -> b -> c) -> (a -> b) -> (a -> a -> c)。请注意末尾 a -> a -> c 周围的括号。
  • 相当于on (*) f x y = f x * f y

标签: haskell type-signature


【解决方案1】:

我的解释是它需要四个参数

所有 Haskell 函数都有一个参数。其中一些只是返回其他函数。

查看on 签名的最佳方法是作为高阶函数:(b -> b -> c) -> (a -> b) -> (a -> a -> c)。这说“如果你给我一个二元运算符,它接受bs 并给出一个c 和一种从as 获得bs 的方法,我会给你一个二元运算符,它接受as并给出c"。您可以在定义中看到这一点:

(*) `on` f = \x y -> f x * f y

【讨论】:

    【解决方案2】:

    函数类型的 Haskell 箭头隐藏了一个简单但聪明的想法。您必须将-> 视为运算符,如+-,但用于类型。它接受两种类型作为参数,并为您提供由函数组成的新类型。所以在

    Int -> String
    

    您有 IntString 类型,并且您获得了一个从 Int 到 String 的函数。

    就像任何其他运算符一样,您需要一个规则链来处理它们。如果你想到-,这是什么意思?

    10 - 6 - 4
    

    (10 - 6) - 4 = 0,还是10 - (6 - 4) = 8?答案是第一个,这就是为什么我们说- 是“左联想”。

    -> 运算符是右结合的,所以

    foo :: Int -> String -> String
    

    其实就是

    foo :: Int -> (String -> String)
    

    想想这意味着什么。这意味着foo 不接受 2 个参数并返回 String 类型的结果,它实际上接受 1 个参数(Int)并返回一个接受第二个参数(String)的新函数和返回最终的String

    函数应用程序的工作方式相同,只是它是左关联的。所以

    foo 15 "wibble"

    其实就是

    (foo 15) "wibble"

    所以foo 应用于15 并返回一个新函数,然后将其应用于"wibble"

    这导致了一个巧妙的技巧:在调用函数时不必提供所有参数(就像在几乎所有其他编程语言中所做的那样),您可以只提供第一个或前几个,然后得到返回一个需要其余参数的新函数。

    on 就是这样。我将使用更具体的版本,其中 'f' 替换为 'length'。

    (*)on 长度

    你给on它的前两个参数。结果是一个需要另外两个的新函数。在类型中,

    on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
    

    在这种情况下,(*) 的类型为 Num n => n -> n -> n(我使用不同的字母以减少混淆),因此它与 on 的第一个参数的类型相匹配,从而得出以下结论:如果类型 bn 替换,然后类型 c 也必须是,并且还必须是 Num 实例。因此length 必须返回一些数字类型。碰巧length 的类型是[d] -> Int,而IntNum 的一个实例,这样就可以了。所以最后你会得到:

    (*) `on` length :: [d] -> [d] -> Int
    

    【讨论】:

      【解决方案3】:

      作为直观的帮助,我将其解读为“如果您给我一个b 类型的比较器,以及一种从a 类型的值中提取b 类型值的方法,我会给你一个a"类型的比较器

      例如如果a是某个复合数据类型,b是这些数据值的某个数值属性,则可以用Data.Function.on表达对这些复合数据类型进行排序的想法。

      【讨论】:

        猜你喜欢
        • 2014-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多