将scala代码概括为一个函数 [英] Generalizing scala code into a function

查看:83
本文介绍了将scala代码概括为一个函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我最近偶然为一个Scala问题写了一个Haskell答案。对于Haskell相当熟悉的解决方案对我来说很容易:

  myMaxBy ::(a  - > a  - >订购) - > [a]  - > [a] 
myMaxBy _ [] = undefined
myMaxBy f(x:xs)= foldr步骤[x] xs
步骤y acc @(z:_)= $ fyz of
GT - > [y]
情商 - > y:acc
LT - > acc

然后有人提醒我这是一个Scala问题。我开始将我的代码转换为Scala,并且经过了很多痛苦之后,我解决了它: :xs.tail){(acc,y)=>
y比较acc.head匹配{
1 =>列表(y)
0 => y :: acc
-1 => acc


$ / code>

但是我不能为我的生活得到Scala类型系统可以按照我的意愿进行操作,并将其概括为一个函数,其中 xs compare 是输入(理想情况下,首先使用比较器的咖喱输入)。虽然这肯定是由于我对Scala的一般陌生性,但我也略微指责了Scala的复杂(虽然非常强大)类型系统。你可以做一些手工操作,并引导我如何将它变成一个广义的函数,其类型签名与Haskell相同? (阅读:一样)。如果它比 myMaxBy(myCompare)(someList)更复杂,请演示使用。

解决方案

您错过了模式匹配中的个案关键字,重要!

您需要的只是集合参数类型能够使用 compare 方法。有两个系统可以比较Scala中的东西:扩展 Ordered ,或者使用 Ordering 。两者之间存在隐式转换,因此您选择的并不重要;第一个也许更容易理解。



首先,使用 Ordered

  def myMaxBy [A<%Ordered [A]](xs:List [A])= {
(List(xs.head)/ :xs.tail){(acc,y)=>
y比较acc.head match {
case 1 =>列表(y)
情况0 => y :: acc
case -1 => acc
}
}
}

使用<%来键入 A a 视图边界,这意味着可以看作是。这比使用上限<:更普遍,并且对于本身不是 Ordered 的类很有用,但隐式转换为 Ordered 类,例如 Int RichInt



或者,如果您想要灵活性可以改变订购标准,你可以这样写:

  def myMaxBy [A](xs:List [A])(隐式ord:排序[A])= {
(List(xs.head)/:xs.tail){(acc,y)=>
ord.compare(y,acc.head)match {
case 1 =>列表(y)
情况0 => y :: acc
case -1 => acc



code $ <$ $ p

当调用时,如果有一个隐含的 Ordering [A] 在范围内,您可以保留第二个参数。第二种方法的优点是,您可以在任意类上定义 Ordering ,无论它们是否已经支持它。



您可以使用例如 myMaxBy(List(1,2,3,4,3,4))来调用它们。在第二种情况下,如果你想要的话,例如,反向排序: myMaxBy(List(1,2,3,4,3,4))(Ordering.Int.reverse)

在这种情况下你可能会看到的另一件事是上下文边界。例如。 [A:订购] 。这意味着与 [A](隐式ord:Ordering [A])相同,它更简洁,除非您没有得到 Ordering ,因此必须使用隐式地来召唤它。所以在这里最好说明如上所述。


So I accidentally wrote a Haskell answer to a Scala question recently. Being rather familiar with Haskell, the solution came quite easily to me:

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

Then someone reminded me that it was a Scala question. I set out to transate my code into Scala, and after much pain I settled for:

(List(xs.head) /: xs.tail) { (acc, y) =>
  y compare acc.head match {
    1  => List(y)
    0  => y :: acc
    -1 => acc
  }
}

But I could not for the life of me get the Scala type system to bend to my will and generalize this into a function where xs and compare are inputs (ideally, curried inputs with the comparator first). Though this is surely due to my general unfamiliarity with Scala, I also slightly blame Scala's complex (though very powerful) type system. Can you do some hand-holding and walk me through how I could turn this into a generalized function, with a type signature similar to the Haskell equivalent? (Read: as general as.) Please also demonstrate usage, if it is more complicated than myMaxBy(myCompare)(someList).

解决方案

You missed out the case keywords in your pattern-match, which are quite important!

All you need is for the collection parameter type to be able to use a compare method. There are two systems for comparing things in Scala: extending Ordered, or using an Ordering. There are implicit conversions between the two so it doesn't matter too much which you choose; the first is perhaps easier to understand.

First off, using 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
      }
    }  
  }

Here we give our generic type A a view bound using <%, which means "can be seen as". This is more general than using an upper bound <:, and useful for classes that are not themselves Ordered, but have implicit conversions to Ordered classes, e.g. Int to RichInt.

Alternatively, if you want flexibility to be able to change the ordering criteria, you can write it like this:

  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
      }
    }
  }

When invoking, if there's an implicit Ordering[A] in scope, you can leave the second argument out. This second way also has the advantage that you can define an Ordering on arbitrary classes, whether or not they already support it.

You can invoke both using, for example, myMaxBy(List(1,2,3,4,3,4)). In the second, if you wanted, say, reverse ordering: myMaxBy(List(1,2,3,4,3,4))(Ordering.Int.reverse).

Another thing you might see in this context are context bounds. E.g. [A: Ordering]. This means the same as [A](implicit ord: Ordering[A]), which is more concise, except that you don't get a handle on the Ordering so have to summon it using implicitly. So here it's probably best to state it explicity as above.

这篇关于将scala代码概括为一个函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆