2016-12-09 1 views
0

Je souhaite implémenter une bibliothèque dans Scala. Je ne fais que commencer et j'ai déjà du mal à le concevoir de manière modulaire et évolutive.Définition de la méthode lors de l'utilisation de type de données algébriques dans Scala

J'ai besoin d'aide! Par exemple, j'ai défini un arbre 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] 

Le Branch_A # représente une fonction avec # arguments. Vous pouvez voir où cela se passe.

Pourquoi A, B et C? Parce que les Leafs seront ex. Double, et j'ai deux types de fonctions Double => Double et (Double, Double) => Double. Je m'inquiète de la façon dont cela va évoluer à mesure que j'augmente la diversité numérique des branches. Je voulais rendre ceci très flexible

J'ai deux questions, une technique, l'autre concernant mon modèle de conception.

Question technique

Lorsque je tente de définir des méthodes génériques pour fonctionner sur de telles structures que je reçois des erreurs de compilation que je ne peux pas résoudre. Par exemple:

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] 

Dans op(evaluateTree(left)) i get "L'application ne supporte pas les paramètres". Je ne comprends pas pourquoi.

design Question

Si l'utilisateur de la bibliothèque doit être autorisé à exprimer un domaine qui fonctionne de arity plus ce sera difficile à gérer. Le nombre de types de génériques va exploser je suppose. Comment puis-je concevoir cela d'une meilleure manière? Je voulais rendre cela évolutif. L'utilisation de types génériques est-elle la plus appropriée? Ou devrait-il une autre façon? J'ai lu que sur les types de données abstraites sont une alternative

+0

'B', comme indiqué dans la méthode evaluateTree, n'est pas nécessaire une fonction' B => C'. Pouvez-vous essayer de déclarer, op dans Branch_A1 comme 'B => C'? Mais cela ne fonctionnerait pas non plus, car evaluateTree donne un 'C', et op attendrait un' B'. – pedrofurla

+0

Réinventez-vous gratuitement? https://www.youtube.com/watch?v = 7xSfLPD6tiQ – Reactormonk

+0

Reactormonk je peux assurer que je n'essaie pas de faire une telle chose! Je suis au début de la programmation fonctionnelle. Je fais principalement de la science des données, donc tous les fondements théoriques de la conception me manquent –

Répondre

0

à la question technique : le compilateur n'a pas assez d'informations sur A ou B savoir si op(...) est possible/permis ou que, si elle est invoquée, il retournerait le type correct.

Et si (pour utiliser un exemple plus simple) vous aviez écrit case Leaf(value) => value-1? Le compilateur n'autorisera pas cela jusqu'à ce que/C ait été défini/limité à un sous-ensemble de types connus pour avoir une méthode -(x:Int) avec un type de retour correspondant.

0

Le jour suivant j'ai regardé de nouveau au problème et tout a fait sens. C'était juste moi qui rendais les génériques beaucoup plus compliqués qu'ils ne le sont en réalité. J'avais précédemment dit que les types génériques [A, B, C] pouvaient signifier par exemple [(Double, Double) => Double, Double => Double, Double]. Donc j'ai juste besoin d'un type paramétré:

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]