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
我正在尝试定义一个函数来求出两个数字的绝对差,使得两者
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