Можно ли построить таблицы поиска функций на основе типов в Scala? - PullRequest
1 голос
/ 07 октября 2019

Я знаю, как это сделать в Lisp / Scheme / Racket, но не в Scala.

// inputType  derives from In  and could be of subtype In1, In2, In3, ...
// outputType derives from Out and could be of subtype Out1, Out2, Out3, ...

def invokeTheRightFunction
  (functionName: Mystery1, inputData: [subtype of In], outputType: Mystery2): Mystery3 =
{
  val lookupTable =
    List( Mystery4(functionName1, inputType1, outputType1),
          Mystery4(functionName2, inputType2, outputType2),
          ...
          Mystery4(functionNameN, inputTypeN, outputTypeN) )
  ...Mystery5...
}

На основе значений functionName, inputType и outputType, заданных inputData который имеет конкретный подтип In, возможно ли использовать построение lookupTable так, чтобы правильная функция вызывалась с inputData, а возвращаемое значение из функции с lookupTable имеет правильный подтип Out?

Если вам интересно, почему я не просто использую match/case, это потому, что я хочу, чтобы в библиотеке был какой-то общий код [обработки базы данных], но код, который использует библиотеку, будетзнать, какие все типы должны входить и выходить.

Код для In, Out и "Mysteries" будет в библиотеке.

Подтипы In и Out и lookupTable будут в коде, который использует библиотеку.

Чтобы сделать это немного более конкретным, допустим, у меня есть [база данных] хранимых процедур A, BC. В настоящее время я помещаю входные данные для этих хранимых процедур в классы дел, называемые ArgsA, ArgsB, ArgsC. Я получаю ответы обратно в виде последовательности RowA, RowB, RowC. Я хочу, чтобы вся или большая часть обработки ошибок происходила в библиотеке.

У моего кода теперь есть некоторое дублирование спецификации типа, и я пытаюсь объединить спецификацию типов в одну таблицу поиска, чтобыуменьшить вероятность ошибки.

1 Ответ

2 голосов
/ 07 октября 2019

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

sealed trait In

case class In1() extends In
case class In2() extends In

sealed trait Out //Mystery2

case class Out1() extends Out
case class Out2() extends Out

sealed trait Name //Mystery1

case class Name1() extends Name
case class Name2() extends Name

sealed trait Row //Mystery3

case class Row1() extends Row
case class Row2() extends Row

Затем мы можем подготовить наш Magnet класс типов:

sealed trait Magnet[N <: Name, I <: Int, O <: Out] {
   type Result <: Row

   def apply(name: N, in: I, out: O): Result
}

Внутри объекта-компаньона Magnet вы можете добавить записи в "lookup" как неявные значения:

import scala.languageFeature.implicitConversions //you can also enable implicit conversions in build.sbt

object Magnet {

  implicit val function1 = new Magnet[Name1, In1, Out2] {
     override type Result = Row1

     override def apply(name: Name1, in: In1, out:Out2): Row1 = ???
  }

  implicit val function2 = new Magnet[Name2, In2, Out1] {
     override type Result = Row2

     override def apply(name: Name2, in: In2, out: Out1): Row2 = ???
  }

}

Наконец, мы можем подготовить invokeTheRightFunction функцию, которая будет неявно требовать Magnet:

def invokeTheRightFunction[N <: Name, I <: Int, O <: Out](name: N, in: I, out: O)(implicit magnet: Magnet[N,I,O]): magnet.Result = magnet(name, in, out)

Давайте проверим это:

val r1: Row1 = invokeTheRightFunction(Name1(), In1(), Out2())

val r2: Row2 = invokeTheRightFunction(Name2(), In2(), Out1())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...