haskell - 函数组合的点表示法

标签 haskell

很抱歉提出一个新手问题。 假设我有:

square :: Integer -> Integer
square x = x * x

我可以用括号进行函数组合:

sumsquares :: Integer -> Integer
sumsquares n = sum (map square [1..n])

但我想使用点符号。我以为这会起作用:

sum . map square [1..n]

但它抛出一个错误:

• Couldn't match expected type ‘a0 -> t0 c0’ with actual type ‘[Integer]’
    • Possible cause: ‘map’ is applied to too many arguments
      In the second argument of ‘(.)’, namely ‘map square [1 .. n]’
      In the expression: sum . map square [1 .. n]
      In an equation for ‘sumsquares’:
          sumsquares n = sum . map square [1 .. n]

(f.g)(x) 逻辑都不起作用,即:

sum . square map [1..n]

我没有得到什么,在这种情况下使用点表示法的正确方法是什么?

最佳答案

(.) 运算符用于组合函数,而不是值,并且它返回的是函数,而不是值。这是因为 f 。 g 被定义为在其输入上运行 g ,然后在其结果上运行 f 所获得的函数:

(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \a -> f (g a)

鉴于此,让我们再次看看您的非工作示例,我将重新括号以使情况更清晰:

sum . map square [1..n]
== (sum) . (map square [1..n])

立刻,我们可以看到一个问题:map square [1..n]不是一个函数!这意味着我们无法在输入上运行它,这又意味着 sum 。 map 方 block [1..n] 没有任何意义。

那么什么是有意义的呢?好吧,我们可以做 sum 。改为 map 正方形。现在 (.) 的两个参数都是函数:sum 求和其输入(必须是数字列表),以及 map squaresquare 应用于其输入的每个元素(必须是数字列表)。因此,它们的组合是有意义的,类型都排列整齐,我们可以毫无问题地使用 (.) 。然后,我们可以通过执行 (sum . map square) [1..n].

向该复合函数提供输入。

另一种选择是使用 ($) 而不是 (.)。该运算符定义如下:

f $ x = f x

也就是说,($) 只是将其左侧的函数应用于其右侧的值!这可能看起来有点没用……但是 ($) 的好处是它的优先级非常低,比 Haskell 中几乎任何其他东西都低。简而言之,这意味着它具有将所有内容“括在”右侧的效果。因此,可以这样写:

sum $ map square [1..n]

…因为这相当于:

sum (map square [1..n])

...这就是您正在尝试做的事情。 (有关 (.)($) 之间差异的更多信息,请参阅 What is the difference between . (dot) and $ (dollar sign)? 。)

关于haskell - 函数组合的点表示法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73589479/

相关文章:

haskell - 何时使用类型族进行类型级计算 "happen"?

haskell - 从列表中删除具有相同值对的元组

api - Haskell GHC API 中的动态编译错误

haskell - Haskell 中的非法多态或限定类型

haskell - 列表列表或元组元组

node.js - 从 Node.JS 调用 Haskell

haskell GHCi 无法导入模块

class - 使一个类成为另一个类的实例

haskell - Haskell单例:排版包

haskell - Haskell 的 $-Operator 的定义