Haskell使用函数Compsition的绝对差异

时间:2017-05-20 02:47:37

标签: haskell function-composition

我正在尝试定义一个函数来找到两个数字的绝对差值,这两个都是

absoluteDifference 2 5
absoluteDifference 5 2

返回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

但我想知道如何撰写这些功能。

4 个答案:

答案 0 :(得分:4)

(.)

的信息
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)

答案 1 :(得分:3)

除了Haleemur Ali's answer所建议的定义自定义运算符之外,还有一种方法是通过将单参数函数作为(.)的第二个参数来使定义更少无点。

absoluteDifference a = abs . (-) a

考虑到函数中两个参数的作用有多么相似,从可读性的角度来看,以这种方式编写它并没有多大意义(尽管在其他情况下可能效果更好)。 / p>

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

absoluteDifference = (abs .) . (-)

虽然这是一个不错的客厅技巧,但这种带有(.)部分的代码相当神秘,通常最好避免它在真实的#34;代码。

答案 2 :(得分:1)

为什么不是猫头鹰操作员?

function zoomIn(i) {
  return new Promise(res => {
   setTimeout(()=>res(i), 1000);
 });
};

function anotherPromise() {
  return Rx.Observable.defer(()=> {
   return new Promise(res => {
     setTimeout(()=>res('anotherPromise'), 3000);
  });
 });
}

const zoonInList = Array(5).fill(0).map((x, i)=>i).map(i=>
   Rx.Observable.defer(()=> {
    return zoomIn(i);
 })
);

Rx.Observable.concat(...zoonInList, anotherPromise())
   .subscribe(x=>console.log(x))

答案 3 :(得分:1)

其实你的答案非常接近。您所需要的只是修改如下;

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

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