Jeśli chcesz użyć tylko standardowej biblioteki scala, spójrz na Numeric[T]
. W twoim przypadku, ponieważ chcesz zrobić podział niecałkowity, będziesz musiał użyć podklasy Fractional[T]
z Numeric
.
Oto, jak kod wyglądałby przy użyciu standardowych czcionek biblioteki scala. Zauważ, że Fractional
rozciąga się od Ordered
. Jest to wygodne w tym przypadku, ale nie jest również matematycznie ogólne. Na przykład. nie można zdefiniować wartości Fractional[T]
dla Complex
, ponieważ nie jest ona uporządkowana.
def bucketiseScala[T: Fractional](buckets: Seq[T], candidate: T): T = {
// so we can use integral operators such as + and/
import Fractional.Implicits._
// so we can use ordering operators such as <. We do have a Ordering[T]
// typeclass instance because Fractional extends Ordered
import Ordering.Implicits._
// integral does not provide a simple way to create an integral from an
// integer, so this ugly hack
val two = (implicitly[Fractional[T]].one + implicitly[Fractional[T]].one)
buckets.foldLeft(buckets.head) { (x, y) =>
val midPoint = (x + y)/two
if (candidate < midPoint) x else y
}
}
Jednak dla poważnych ogólnych obliczeń numerycznych Chciałbym zasugerować przyjrzeniu spire. Zapewnia znacznie bardziej rozbudowaną hierarchię liczbowych typów. Typy maszyn iglica są również wyspecjalizowane, a zatem często tak szybkie, jak praca bezpośrednio z prymitywami.
Oto jak używać przykład wyglądałby za pomocą iglicy:
// imports all operator syntax as well as standard typeclass instances
import spire.implicits._
// we need to provide Order explicitly, since not all fields have an order.
// E.g. you can define a Field[Complex] even though complex numbers do not
// have an order.
def bucketiseSpire[T: Field: Order](buckets: Seq[T], candidate: T): T = {
// spire provides a way to get the typeclass instance using the type
// (standard practice in all libraries that use typeclasses extensively)
// the line below is equivalent to implicitly[Field[T]].fromInt(2)
// it also provides a simple way to convert from an integer
// operators are all enabled using the spire.implicits._ import
val two = Field[T].fromInt(2)
buckets.foldLeft(buckets.head) { (x, y) =>
val midPoint = (x + y)/two
if (candidate < midPoint) x else y
}
}
Spire nawet zapewnia automatyczną konwersję z liczb całkowitych do T
jeśli istnieje Field[T]
, więc można nawet napisać przykład tak (prawie identyczną wersja nietypowa). Myślę jednak, że powyższy przykład jest łatwiejszy do zrozumienia.
// this is how it would look when using all advanced features of spire
def bucketiseSpireShort[T: Field: Order](buckets: Seq[T], candidate: T): T = {
buckets.foldLeft(buckets.head) { (x, y) =>
val midPoint = (x + y)/2
if (candidate < midPoint) x else y
}
}
Aktualizacja: iglica jest bardzo potężna i generyczna, ale może również wprowadzać w błąd początkującego. Zwłaszcza, gdy coś nie działa. Oto excellent blog post wyjaśniające podstawowe podejście i niektóre z problemów.
OK, dzięki temu sprawdzę iglicę. Chodzi o to, że scala docs dla Int (http://www.scala-lang.org/api/current/index.html#scala.Int) nie wymienia cech, które rozszerza, więc doszedłem do zgadywania o 'Zamawianiu '. Jak mogę się dowiedzieć, jakie cechy rozszerza "Int", aby móc znaleźć "Numeric [T]" dla siebie? – jbrown
@jbrown Ordering to [typeclass] (http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html). Typy nie działają z dziedziczeniem. –
W jaki sposób mogłem wiedzieć, patrząc na dokumenty, jakie typologie odnoszą się do Int? – jbrown