2017-11-01 8 views
3

私は、値としてサポートできる型では固定されていないDSLを設計しようとしています。値の型が固定されていないScala DSL

以下、これを達成するために、Value typeclassを使用しています。意図されたアプリケーションでは動作しますが、動作はありません。

trait Value[T] 
object Value { 
    implicit object IntIsValue extends Value[Int] 
    implicit object StringIsValue extends Value[String] 
} 

DSLは、金額ベースおよびアプリケーション用語で構成されています。私は、コンパイルの問題を持っているところ

abstract class Term[T: Value] 
case class ValueTerm[T: Value](x: T) extends Term[T] 
case class AppTerm[Arg: Value, T: Value](fun: Arg => T, arg: Term[Arg]) extends Term[T] 

評価関数は次のとおりです。

def eval[T: Value](term: Term[T]): T = { 
    term match { 
    case ValueTerm(x) => x 
    case AppTerm(fun, arg) => fun(eval(arg)) // doesn't compile 
    } 
} 

ここで私が得る代表コンパイルエラーです

Error:(14, 40) could not find implicit value for evidence parameter of type A$A354.this.Value[Any] 
    case AppTerm(fun, arg) => fun(eval(arg)) 
            ^

コンパイラはargTerm[Any]と考えており、それがValueのインスタンスであることはわかりません。

Valueの制約をevalから削除することで回避できます。しかし、その後、私はValueの行動を失い、私はevalに使用する場合があります:

def eval[T](term: Term[T]): T -- loses behaviour of Value typeclass 

これは、コンパイル、そしてどのよう

  • ない理由だから私の質問は

    1. だろうこのようなものを達成するために

    はここにDSLのいくつかの使い方です:

    val i41: Term[Int] = ValueTerm(41) 
    val i42: Term[Int] = AppTerm(fun = (_: Int) + 1, arg = i41) 
    val theAnswer: Term[String] = AppTerm(fun = "The answer is " ++ (_: Int).toString, arg = i42) 
    
    eval(i41) 
    eval(i42) 
    eval(theAnswer) 
    
  • +0

    'Any'で示されているように、型情報を失うので、パス依存型がここでの答えだと思います。 – Reactormonk

    答えて

    1

    問題は用語が彼らと必要な暗黙しかし、彼らは自動的に暗黙のスコープの一部ではない、そのように運んでいるということです。迅速な修正はValue[Arg]を公開する方法をAppTermに追加することです。それを明示的にevalに渡すことができます。

    def eval[T: Value](term: Term[T]): T = { 
        term match { 
        case ValueTerm(x) => x 
        case t @ AppTerm(fun, arg) => fun(eval(arg)(t.implicitArg)) 
        } 
    } 
    

    ただし、ソリューションを少し違った方法で設計したいという兆候と思われるかもしれません。たとえば、Termの暗黙的なValueをキャプチャし、次にevalには、Termを渡して暗黙的にValueを渡すことは危険です。そのため、別のValueevalに渡して、Termに取り込まれたものを渡すことは可能です。

    関連する問題