2017-08-11 6 views
15

簡単な最小限の例を作成する目的で、ラムダの例として=:=を使用しました。タイプラムダを正しく定義するには?

=:=タイプは2つの引数を取るので、タイプレベルで1つカレーしたいと思います。

私はナイーブな実装type Curry[G] = {type l[L] = L =:= G}を取ることが、実用的には、それはエラーが発生し使用しています。

type X = Int 
type Y = Int 

type CurryInt[T] = T =:= Int 
type Curry[G] = {type l[L] = L =:= G} 
type CurrStatic = {type l[L] = L =:= Int} 
object CurryObj {type l[L] = L =:= Int} 

trait Apply[P[_], T] 
implicit def liftApply[P[_], T](implicit ev : P[T]) = new Apply[P,T] {} 

implicitly[Apply[CurryInt, Y]] // ok 
implicitly[Apply[Curry[X]#l, Y]] // fails 
implicitly[Apply[Curry[X]#l, Y]](liftApply) // fails 
implicitly[Apply[Curry[X]#l, Y]](liftApply[Curry[X]#l, Y]) // ok 
implicitly[Apply[CurrStatic#l, Y]] // fails 
implicitly[Apply[CurryObj.l, Y]] // ok 

型推論がここに壊れます。タイプlambdaを定義するにはどのようにすればいいですか?

答えて

2

やや冗長な、しかしコンパイル:)(スカラ座2.12.3)

type X = Int 
    type Y = Int 

    type CurryInt[T] = T =:= Int 
    type Curry[G] = {type l[L] = =:=[L, G]} 
    type CurrStatic = {type l[L] = L =:= Int} 
    object CurryObj {type l[L] = L =:= Int} 

    trait Apply[P[_], T] 
    implicit def liftApply[P[_], T](implicit ev : P[T]) = new Apply[P,T] {} 


    type L1[R] = =:=[R, X] 
    type L2[R] = =:=[R, Int] 
    implicitly[Apply[CurryInt, Y]] // ok 
    implicitly[Apply[L1, Y]] // ok 
    implicitly[Apply[L1, Y]](liftApply[L1, Y]) // ok 
    implicitly[Apply[Curry[X]#l, Y]](liftApply[Curry[X]#l, Y]) // ok 
    implicitly[Apply[L2, Y]] // ok 
    implicitly[Apply[CurryObj.l, Y]] // ok 
+0

まもなくタイププロジェクションを使用しません。型宣言にはバインドされていない変数があることが許可されています – ayvango

+0

あなたはあなたの要件に関して具体的ではありませんでしたが、このソリューションは「型投影」に取り組もうとしていますか?練習問題ですか? – pedromss

+0

タイプの式にバインドされていない型が許可されていないことに気がつきました。だからタイプレベルで 'λx.λy.x== y'のようなものをエンコードしようとしました。私は単純な 'λx.x== y'が正しいスカラー表現であるとは想像できませんでした。 – ayvango

3

はあなたの例のこの簡易版考えてみます。

trait Secret 
type Curry = { type l[L] = Secret } 

def foo[P[_], T](ev : P[T]) = ??? 
val bar: Curry#l[Int] = ??? 

foo(bar) 

を値barが単純であるfooを呼び出すときSecretのタイプの場合、コンパイラはあなたの特定のSecretの出所を知らない。

barの値はちょうどSecretであり、Curry#l[Int]を指す情報は保持されません。

コンパイラは、P => Curry#lT => Intと推測できません。

コンパイラはSecretを見て、Curry#l[Int]代わりのSecretと種類に注釈を付けるにもかかわらず、Curry#lコンテキストを失います。

this質問から来て)別の例として、同様の行動を暴露:

trait Curry { type l } 
trait CurryB extends Curry { type l = String } 

def foo[P <: Curry](x: P#l) = ??? 
val bar: CurryB#l = ??? 

foo(bar) 

CurryObj状況がCurryInt#lCurry#l、およびCurrStatic#lだけのエイリアスを入力していることを考慮し、異なっています。代わりにCurryObj.lが実際のタイプであり、具体的なオブジェクトCurryObjの一部です。

はのは、この(REPL)を見てみましょう:タイプの別名 Curry#l[Int]こと

scala> trait Secret 
defined trait Secret 

scala> type Curry = { type l[L] = Secret } 
defined type alias Curry 

scala> object CurryObj { type l[L] = Secret } 
defined object CurryObj 

scala> object S extends Secret 
defined object S 

scala> val foo0: Curry#l[Int] = S 
foo0: Secret = [email protected] 

scala> val foo1: CurryObj.l[Int] = S 
foo1: CurryObj.l[Int] = [email protected] 

注 - >Secretは、すぐに代わりに実際の型CurryObj.l[Int]保たれているが解消されます。

+0

タイプ 'Curry'は、私の例では' CurrStatic'と似ています。 'CurryObj'と非常によく似ています。なぜ型情報が1つのケースに保存され、別のケースに格納されるのですか? – ayvango

+0

私はあなたの懸念に対処するための答えを更新しました。 –

+0

意味があります。しかし私の場合、 'Curry#l'は' Int'をそれに適用することなく使われます。また、「秘密」も型パラメータを持っているので、排除することはできません。 '-Yinfer-debug'で見たように、型パラメータは保存されているが普通ではない形式である – ayvango

0

scalaコンパイラが型投影から裸の型を処理できなかったようです。私は-Ytyper-debugの出力をトレースし、必要なすべてのタイプ情報が持ち去られているが、明白な理由で拒否されていることがわかりました。しかし、ラムダ型ラップを式の中に入れることは、まだ可能です。 That answerは私に解決策の洞察を与えました。

type X = Int 
type Y = Int 

trait Wrap { 
    type l[T] 
} 
trait GenWrap[W[_]] extends Wrap { 
    final type l[T] = W[T] 
} 

type CInt[T] = T =:= Int 
class CurryInt extends Wrap {type l[T] = T =:= Int} 
class Curry[U] extends Wrap {type l[T] = T =:= U} 
type TCurry[U] = Wrap {type l[T] = T =:= U} 

trait Apply[W <: Wrap, T] 
implicit def lift[W <: Wrap, T](implicit ev : W#l[T]) = new Apply[W,T] {} 

implicitly[Apply[CurryInt, Y]] 
implicitly[Apply[Curry[X], Y]] 
implicitly[Apply[TCurry[X], Y]] 
implicitly[Apply[GenWrap[CInt], Y]] 
関連する問題