Scala: Как определить “универсальные” параметры функции?

Я думаю в ГРУШЕВОЙ документации, существует рекомендация для, требуют, require_once, включают и include_once. Я действительно следую той инструкции. Ваше приложение было бы более четким.

51
задан Dan Burton 8 September 2011 в 04:37
поделиться

5 ответов

Haskell использует алгоритм вывода типа Хиндли-Милнера, тогда как Scala, чтобы поддерживать объектно-ориентированную сторону вещей, на данный момент вынужден был отказаться от его использования.

Чтобы легко написать функцию добавления для всех применимых типов, вам понадобится Scala 2.8.0:

Welcome to Scala version 2.8.0.r18189-b20090702020221 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_15).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import Numeric._
import Numeric._

scala> def add[A](x: A, y: A)(implicit numeric: Numeric[A]): A = 
     | numeric.plus(x, y)
add: [A](x: A,y: A)(implicit numeric: Numeric[A])A

scala> add(1, 2)
res0: Int = 3

scala> add(1.1, 2.2)
res1: Double = 3.3000000000000003
68
ответ дан 7 November 2019 в 10:09
поделиться

Сама функция будет будьте довольно прямолинейны:

def add(x: T, y: T): T = ...

А еще лучше, вы можете просто перегрузить метод +:

def +(x: T, y: T): T = ...

Однако здесь отсутствует часть, которая является самим параметром типа. Как написано, у метода отсутствует свой класс. Скорее всего, вы

1
ответ дан 7 November 2019 в 10:09
поделиться

Haskell использует вывод типа Хиндли-Милнера . Этот вид вывода типов является мощным, но ограничивает систему типов языка. Предположительно, например, создание подклассов плохо работает с HM.

В любом случае, система типов Scala слишком мощна для HM, поэтому необходимо использовать более ограниченный вид вывода типов.

3
ответ дан 7 November 2019 в 10:09
поделиться

Я думаю, что причина, по которой Scala требует аннотации типа для параметров вновь определенной функции, исходит из того факта, что Scala использует более локальный анализ вывода типов, чем тот, что используется в Haskell.

Если все ваши классы смешаны в признаке, скажем Addable [T] , который объявил оператор + , вы можете написать свою общую функцию добавления как:

def add[T <: Addable[T]](x : T, y : T) = x + y

Это ограничивает функцию добавления до типы T, которые реализуют признак Addable

К сожалению, в текущих библиотеках Scala такой особенности нет. Но вы можете увидеть, как это было бы сделано, посмотрев на аналогичный случай - черту Ordered [T] . Эта черта объявляет операторы сравнения и смешивается с классами RichInt , RichFloat и т. Д. Затем вы можете написать функцию сортировки, которая может принимать, например, a Список [T] , где [T <: Ordered [T]] для сортировки списка элементов, которые смешиваются в упорядоченном признаке. Из-за неявного преобразования типов, например Float в RichFloat , вы даже можете использовать функцию сортировки в списках Int или Float или Double .

Как я уже сказал, к сожалению, для оператора + нет соответствующей черты. Значит, вам придется все выписывать самому. Вы должны использовать трейт Addable [T], создать AddableInt , AddableFloat и т. Д., Классы, расширяющие Int, Float и т. Д., И смешать трейт Addable, и, наконец, добавить неявный функции преобразования для преобразования, например, и Int в AddableInt ,

3
ответ дан 7 November 2019 в 10:09
поделиться

Чтобы укрепить концепцию использования неявного для себя, я написал пример, который не требует scala 2.8, но использует ту же концепцию. Я подумал, что это может быть полезно для некоторых. Сначала вы определяете обобщенно-абстрактный класс Addable :

scala> abstract class Addable[T]{
 |   def +(x: T, y: T): T
 | }
defined class Addable

Теперь вы можете написать функцию add следующим образом:

scala> def add[T](x: T, y: T)(implicit addy: Addable[T]): T = 
 | addy.+(x, y)
add: [T](T,T)(implicit Addable[T])T

Это используется как класс типов в Haskell. Затем, чтобы реализовать этот универсальный класс для определенного типа, вы должны написать (примеры здесь для Int, Double и String):

scala> implicit object IntAddable extends Addable[Int]{
 |   def +(x: Int, y: Int): Int = x + y
 | }
defined module IntAddable

scala> implicit object DoubleAddable extends Addable[Double]{
 |   def +(x: Double, y: Double): Double = x + y
 | }
defined module DoubleAddable

scala> implicit object StringAddable extends Addable[String]{
 |   def +(x: String, y: String): String = x concat y
 | }
defined module StringAddable

На этом этапе вы можете вызвать функцию add с все три типа:

scala> add(1,2)
res0: Int = 3

scala> add(1.0, 2.0)
res1: Double = 3.0

scala> add("abc", "def")
res2: java.lang.String = abcdef

Конечно, не так хорош, как Haskell, который, по сути, сделает все это за вас. Но в этом и заключается компромисс.

18
ответ дан 7 November 2019 в 10:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: