很抱歉提出一个新手问题。 假设我有:
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 square
将 square
应用于其输入的每个元素(必须是数字列表)。因此,它们的组合是有意义的,类型都排列整齐,我们可以毫无问题地使用 (.)
。然后,我们可以通过执行 (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/