Dan*_*ton 9 generics haskell types scala function
所以我最近不小心写了一个关于Scala问题的Haskell答案.对Haskell比较熟悉,解决方案对我来说非常容易:
myMaxBy :: (a -> a -> Ordering) -> [a] -> [a]
myMaxBy _ [] = undefined
myMaxBy f (x:xs) = foldr step [x] xs
where step y acc@(z:_) = case f y z of
GT -> [y]
EQ -> y:acc
LT -> acc
Run Code Online (Sandbox Code Playgroud)
然后有人提醒我这是一个Scala问题.我开始将我的代码转换为Scala,经过多次努力后我决定:
(List(xs.head) /: xs.tail) { (acc, y) =>
y compare acc.head match {
1 => List(y)
0 => y :: acc
-1 => acc
}
}
Run Code Online (Sandbox Code Playgroud)
但我不能为我的生活让Scala类型系统屈服于我的意愿并将其概括为一个函数,其中xs和compare是输入(理想情况下,首先是比较器的咖喱输入).虽然这肯定是由于我对Scala的一般不熟悉,但我也略微责怪Scala的复杂(虽然非常强大)类型系统.你可以做一些手握,并指导我如何把它变成一个通用函数,类型签名类似于Haskell等价?(阅读:如同一般.)如果比它更复杂,也请证明用法myMaxBy(myCompare)(someList).
Lui*_*hys 13
你错过了case模式匹配中的关键字,这非常重要!
您只需要集合参数类型就可以使用compare方法.在Scala中有两个用于比较事物的系统:扩展Ordered或使用Ordering.两者之间存在隐含的转换,因此您选择的内容并不重要; 第一个可能更容易理解.
首先,使用Ordered:
def myMaxBy[A <% Ordered[A]](xs: List[A]) = {
(List(xs.head) /: xs.tail) { (acc, y) =>
y compare acc.head match {
case 1 => List(y)
case 0 => y :: acc
case -1 => acc
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们给我们的通用型A一束缚视图使用<%,意思是"可以被看作是".这比使用上限更普遍<:,而对于不属于自己的类有用Ordered,但有隐式转换为Ordered类,如Int到RichInt.
或者,如果您希望能够灵活地更改排序条件,则可以这样写:
def myMaxBy[A](xs: List[A])(implicit ord: Ordering[A]) = {
(List(xs.head) /: xs.tail) { (acc, y) =>
ord.compare(y, acc.head) match {
case 1 => List(y)
case 0 => y :: acc
case -1 => acc
}
}
}
Run Code Online (Sandbox Code Playgroud)
在调用时,如果Ordering[A]范围中存在隐式,则可以保留第二个参数.第二种方式还有一个优点,即您可以定义Ordering任意类,无论它们是否已经支持它.
例如,您可以使用两者来调用myMaxBy(List(1,2,3,4,3,4)).在第二种情况下,如果你想要反向排序: myMaxBy(List(1,2,3,4,3,4))(Ordering.Int.reverse).
您可能在此上下文中看到的另一件事是上下文边界.例如[A: Ordering].这意味着相同[A](implicit ord: Ordering[A]),更简洁,除了你没有得到一个句柄,Ordering所以必须使用它来召唤它implicitly.所以在这里最好如上所述明确说明.
| 归档时间: |
|
| 查看次数: |
628 次 |
| 最近记录: |