2016-12-09 7 views
0

Я хочу реализовать библиотеку в Scala. Я только начинаю, и у меня уже возникли проблемы с его модульным и масштабируемым способом.Определение метода при использовании Алгебраических данных в Scala

Мне нужна помощь! Например я определил дерево ADT

sealed trait Tree[+A,+B,+C] 
case object EmptyTree extends Tree[Nothing, Nothing, Nothing] 
case class Leaf[A,B,C](value: C) extends Tree[A,B,C] 
case class Branch_A1[A,B,C](op: B, left: Tree[A,B,C]) extends Tree[A,B,C] 
case class Branch_A2[A,B,C](op: A, left: Tree[A,B,C], right: Tree[A,B,C]) extends Tree[A,B,C] 

Branch_A # представляет собой функцию с # аргументов. Вы можете видеть, где это происходит.

Почему A, B и C? Поскольку Листы будут, например, Двойной, и у меня есть два типа функций Double => Double и (Double, Double) => Double. Я беспокоюсь о том, как это будет масштабироваться, поскольку я увеличиваю число разнообразия филиалов. Я хотел бы сделать это очень гибким

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

технический вопрос

Когда я пытаюсь определить общие методы для работы на таких структурах я получаю ошибки компиляции, которые я не могу решить. Например:

sealed trait Tree[+A,+B,+C] { 
    def evaluateTree[A,B,C] (t: Tree[A,B,C]): C = t match { 
    case Leaf(value) => value 
    case Branch_A1(op, left) => op(evaluateTree(left)) 
    case Branch_A2(op, left, right) => op(evaluateTree(left),evaluateTree(right)) 
    } 
} 
case object EmptyTree extends Tree[Nothing, Nothing, Nothing] 
case class Leaf[A,B,C](value: C) extends Tree[A,B,C] 
case class Branch_A1[A,B,C](op: B, left: Tree[A,B,C]) extends Tree[A,B,C] 
case class Branch_A2[A,B,C](op: A, left: Tree[A,B,C], right: Tree[A,B,C]) extends Tree[A,B,C] 

В op(evaluateTree(left)) я получаю «Приложение не поддерживает параметры». Я не могу понять, почему.

Дизайн Вопрос

Если пользователь библиотеки должен иметь возможность выразить домен высшие функции Arity это будет трудно управлять. Количество типов дженериков взорвется, я думаю. Как я могу разработать это лучше? Я хотел сделать это масштабируемым. Является ли использование общих типов наиболее подходящим? Или должен другой путь? Я читал, что о абстрактные типы данных являются альтернативой

+0

'B', как указано в методе метода оценки, не требуется функция' B => C'. Можете ли вы попытаться объявить, op в Branch_A1 как 'B => C'? Но это тоже не сработает, потому что valuTree дает 'C', а op будет ожидать' B'. – pedrofurla

+0

Вы изобретаете Free? https://www.youtube.com/watch?v = 7xSfLPD6tiQ – Reactormonk

+0

Reactormonk Я могу заверить, что я не пытаюсь это делать! Я нахожусь в начале функционального программирования. Я в основном занимаюсь наукой о данных, поэтому я пропустил все теоретические основы дизайна –

ответ

0

К Технический Вопрос: компилятор не имеет достаточной информации о A или B знать, если op(...) возможно/разрешено или что, если вызван, он вернется правильный тип.

Что делать, если (для использования более простого примера) вы написали case Leaf(value) => value-1? Компилятор не разрешит это до тех пор, пока C не будет определен/ограничен некоторым подмножеством типов, которые, как известно, имеют метод -(x:Int) с соответствующим типом возврата.

0

На следующий день я снова посмотрел на проблему, и все это имело смысл. Просто я делал дженерики намного сложнее, чем они есть на самом деле.

Ранее я говорил, что типы дженериков [A, B, C] могут означать, например, [(Double, Double) => Double, Double => Double, Double]. Поэтому мне нужен только один параметризованный тип:

sealed trait Tree[+A] 
case object EmptyTree extends Tree[Nothing] 
case class Leaf[A](value: A) extends Tree[A] 
case class Branch_A1[A](op: A => A, left: Tree[A]) extends Tree[A] 
case class Branch_A2[A](op: (A,A) => A, left: Tree[A], right: Tree[A]) extends Tree[A] 

 Смежные вопросы

  • Нет связанных вопросов^_^