我对组成的理解差距,类型不匹配

par*_*and 3 lambda haskell function function-composition

在我的代码中,我需要(Int, Int)按第二个元素的值对s 列表进行排序.

这很容易做到sorted = sortBy (\(_,a) (_,b) -> compare a b) listOfPairs,但我讨厌像这样写lambda,我需要在我的代码中的几个地方使用相同的lambda.

所以我试着创建两个有用的函数,我最终会在很多地方使用如下(我在前奏中找不到它们):

-- apply a function of one argument to two different arguments and return a pair
fBoth :: (a -> b) -> a -> a -> (b,b)
fBoth f a b = (f a, f b)

-- pass elements of a pair to a function of two arguments
expandPair :: (a -> b -> c) -> (a,b) -> c
expandPair f (a,b) = f a b
Run Code Online (Sandbox Code Playgroud)

现在我想我能够一起创造一些东西sortBy而不是一个丑陋的"提取器"lambda.但我不能让这些类型排成一列.

我觉得我想要(expandPair compare)与之合作(fBoth snd),因为:t expandPair compare = (a,a) -> Ordering:t fBoth snd = (a,b) -> (a,b) -> (b,b).我认为这种组合的结果类型将是(a,b) -> (a,b) -> Ordering我可以传递给sortBy它的,但它并不是很有效.

如果我尝试这样做sortBy ((expandPair compare) . (fBoth snd)) [(1,2),(3,4)]会给我类型错误.但令我困惑的是,如果我这样做,expandPair compare $ fBoth snd (1,2) (3,4)它实际上是LT按预期工作和收益的.

很明显我在这里不了解一些关于函数组合的东西...我得到了整个"用f = g(f(x))组成的",但是我在这里让它对我有用了.

或者,如果有一种更简单的方法来完成第二个元素排序对列表的特定任务,我也有兴趣听到它.

bhe*_*ilr 7

首先,你的expandPair作用是字面上的定义相同uncurry,这是Prelude.

这里的问题是fboth snd需要2个参数,因此普通的合成运算符不太适合这个任务.但是,您可以创建一个看起来很奇怪的运算符,它允许您"组合"一个带有两个参数的函数,该函数带有一个带有1个参数的函数:

(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.).(.)
Run Code Online (Sandbox Code Playgroud)

记住这个的简单助记符是,带有一个点的一侧的函数采用1个参数,与带有两个参数的函数的输出相同,在两侧有两个点.然后你可以把它写成

sortBy (uncurry compare .: fboth snd) [(1, 2), (3, 4)]
Run Code Online (Sandbox Code Playgroud)

现在,我会说最好不要真正考虑.:运算符的工作原理,只看它的类型而不是它的定义.它确实经常使用,我经常使用它,我当然没有提出这个运算符.


您也可以将其实现为

> :m +Data.Function
> sortBy (compare `on` snd) ...
-- sortBy (on compare snd) ...
Run Code Online (Sandbox Code Playgroud)

但正如@mhwombat指出的那样,Data.Ord有一个on compare名为的别名comparing:

> :m +Data.Ord
> sortBy (comparing snd) ...
Run Code Online (Sandbox Code Playgroud)

这是我的偏好.


可能会使这个操作符更清晰的东西:

> :t (id .: (,))
a -> b -> (a, b)
> (id .: (,)) 1 2
(1, 2)
> (fst .: (,)) 1 2
1
> (snd .: (,)) 1 2
2
> (negate .: (+)) 1 2
-3
Run Code Online (Sandbox Code Playgroud)