将scala代码推广到函数中

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类型系统屈服于我的意愿并将其概括为一个函数,其中xscompare是输入(理想情况下,首先是比较器的咖喱输入).虽然这肯定是由于我对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类,如IntRichInt.

或者,如果您希望能够灵活地更改排序条件,则可以这样写:

  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.所以在这里最好如上所述明确说明.

  • 你可以将`import Ordering.Implicits._`放在文件的顶部,从而避免在整个地方发出"隐式"召唤. (2认同)