Haskell 使用函数组合的绝对差

Haskell Absolute Difference Using Function Compsition

我正在尝试定义一个函数来求出两个数字的绝对差,使得两者

absoluteDifference 2 5
absoluteDifference 5 2

return 3.

这是我迄今为止的最大努力:

absoluteDifference :: Num a => a -> a -> a
absoluteDifference = abs . (-)

在我看来,这适用于 abs 两个数字相减的结果。但是,这给了我错误

* Could not deduce (Num (a -> a)) arising from a use of `abs'
    (maybe you haven't applied a function to enough arguments?)
  from the context: Num a
    bound by the type signature for:
               absoluteDifference :: Num a => a -> a -> a
    at C:\Users\Adam\dev\daily-programmer\e311\e311.hs:3:1-42
* In the first argument of `(.)', namely `abs'
  In the expression: abs . (-)
  In an equation for `absoluteDifference':
      absoluteDifference = abs . (-)

我不明白。我可以简单地将函数实现为

absoluteDifference a b = abs $ a - b

但我想知道如何组合函数。

(.)

的信息
Prelude> :i (.)
(.) :: (b -> c) -> (a -> b) -> a -> c   -- Defined in ‘GHC.Base’

表明它接受类型为 a -> b

的函数

但是 (-) 的类型是

Prelude> :i (-)
class Num a where
  ...
  (-) :: a -> a -> a
  ...
    -- Defined in ‘GHC.Num’
infixl 6 -

因此,可以定义另一个组合运算符来接受具有上述类型的函数,然后它们就可以组合了。

of' :: (a -> a) -> (a -> a -> a) -> a -> a -> a
of' f g a b = f (g a b)

abdiff = abs `of'` (-)

abdiff 1 10
9

注意:正如用户@david-young 正确指出的那样,of' 可以通过指定以下类型来更通用:

of' :: (a -> b) -> (c -> d -> a) -> c -> d -> b
of' f g x y = f (g x y)

为什么不是 owl 运算符?

(...) = (.) . (.)
absoluteDifference = abs ... (-)

除了按照 的建议定义自定义运算符之外,另一种方法是通过将单参数函数作为 (.) 的第二个参数来使定义不那么无意义。

absoluteDifference a = abs . (-) a

鉴于函数中两个参数的作用非常相似,从可读性的角度来看,以这种方式编写它没有多大意义(尽管在其他情况下它可能会更好)。

另一种可能性是让它更无意义(通过将函数修改函数作为 (-) 的第一个参数):

absoluteDifference = (abs .) . (-)

虽然这是一个很好的客厅技巧,但这种带有 (.) 部分的代码相当神秘,通常最好在 "real" 代码中避免它。

其实你的答案很接近。您只需修改如下即可;

absDiff :: Num a => a -> a -> a
absDiff n = abs . (n-)

*Main> absDiff 3 9
6
*Main> absDiff 9 3
6