У меня есть некоторые параметры, которые, когда они отсутствуют, я не хочу, чтобы функция моего преобразования не выполнялась.Классы типа Scala для преобразования по опции с использованием функций более высокого порядка
Метод, который в настоящее время обрабатывает параметры выглядит следующим образом:
def writeOptionalXml[T](content: Option[T], mapFn: T => Xml): Xml =
content match {
case Some(c) => mapFn(c)
case None => NodeSeq.Empty
}
И он прекрасно работает. Но у меня также есть другие входы, которые не являются параметрами, но все равно могут быть пустыми, например пустая строка, пустой узел xml или некоторый класс case.
Я думал, что это будет хорошее обучение для меня, чтобы реорганизовать класс типа. После многократного перебора кода я обнаружил, что мне нужно использовать границы контекста, чтобы обрабатывать тип параметра, и думал, что я был на пути к достижению мечты типа класса.
Где я застрял - это функция преобразования (плохо названная в качестве mapFn). В случае отсутствия опции я хочу, чтобы подпись метода: (содержимое: опция [T], mapFn: T => Xml): Xml , тогда как в других случаях: (вход: A, mapFn: A => Xml) : Xml
Я боролся с изменением подписей типа, используя [_], чтобы попытаться получить то, что я хочу, но безрезультатно.
синтезированный вариант кода у меня есть на данный момент, что угодно, но довольно, выглядит следующим образом:
import scala.annotation.implicitNotFound
object writableTypes extends App {
type Xml = String
@implicitNotFound("No member of type class in scope for ${T}")
trait WritableLike[A] {
def toXml[B](input: A, mapFn: ((_$1) forSome {type _$1}) => Xml): Xml
}
object WritableLike {
implicit object WritableLikeString extends WritableLike[String] {
override def toXml[B](input: String, mapFn: ((_$1) forSome {type _$1}) => Xml): Xml =
mapFn(input)
}
implicit def OptionFormat[T: WritableLike]: Object = new WritableLike[Option[T]] {
override def toXml[B](input: Option[T], mapFn: ((_$1) forSome {type _$1}) => Xml): Xml =
mapFn(input.get)
}
def writeXml[X](input: X, mapFn: ((_$1) forSome {type _$1}) => Xml)(implicit ev: WritableLike[X]): Xml =
ev.toXml[X](input, mapFn)
}
println(WritableLike.writeXml(Option(SomeCaseClass(5)), transformToXml))
case class SomeCaseClass(content: Int) { def someMethod = ""}
def transformToXml[T](input: SomeCaseClass): String = input.someMethod
}
К сожалению, это не компилируется, потому что в этом вызов метода WritableLike.writeXml (вариант (SomeCaseClass (5)), transformToXml)
Функция transformToXml не удовлетворяет требуемой сигнатуре метода.
Я пробовал так много перестановок этого и не могу найти решение, элегантное в противном случае.
Уверен, что есть простые способы решить эту проблему, сделав все возможной, но меня больше интересует поиск решения, чтобы сделать его общепринятым.
Я не уверен, что объяснил это очень хорошо, это моя первая попытка написать класс типа, я думал, что это будет просто, но похоже, что конкретная проблема, которую я пытаюсь решить, имеет некоторые дополнительные сложности.
Буду признателен, если вы услышите от кого-то более глубокое понимание общего программирования с системой типа Scala.
Благодаря
Надеюсь, этот ответ поможет. Если у вас есть какие-либо вопросы, просто прокомментируйте здесь, и я увижу, могу ли я расширить свой ответ. :) –
Привет Яко спасибо за ваш ответ. В более широком контексте имеется несколько форматировщиков, каждый из которых генерирует xml NodeSeqs из комбинации классов case, строк, дат, других nodeseq и т. Д. (Как NodeSeq). Иногда есть пустые строки, nodeseqs или Option [caseclass] of None. Иногда класс case используется в нескольких местах (для форматирования) для генерации разных частей документа xml с различными тегами xml, поэтому гибкость генерации узла с переданной функцией имеет решающее значение. –
Деловое дело в порядке, однако я хотел исследовать мощность и ограничения типа класса в Scala. Возможно, это предел языка или рисунка? Просто кажется, что это должно быть возможно. –