2017-08-11 8 views
15

J'ai utilisé =:= comme exemple de type lambda dans le but de faire un exemple minimal simple. TapezComment définir correctement le type lambda?

=:= tapez deux arguments, je voudrais en écrire un au niveau du type.

Je prends la mise en œuvre naïve type Curry[G] = {type l[L] = L =:= G} mais utilise en pratique, il provoque des erreurs:

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 

inférence de type casse ici. Comment devrais-je définir le type lambdas pour le faire fonctionner?

Répondre

2

un peu plus bavard, mais compilera :) (scala 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

brièvement: n'utilise pas la projection de type.Les déclarations de type peuvent avoir des variables non liées – ayvango

+0

Vous n'étiez pas spécifique quant à vos besoins, mais cette solution compile pourquoi essayez-vous d'aller avec la 'projection de type'? Est-ce juste un exercice? – pedromss

+0

J'étais inconscient que les types non liés sont autorisés dans l'expression de type. J'ai donc essayé d'encoder quelque chose comme 'λx.λy.x == y' au niveau du type. Je ne pouvais pas imaginer que le simple 'λx.x == y' serait une expression correcte de scala. – ayvango

3

cette version simplifiée Tenir compte de votre exemple:

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

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

foo(bar) 

Lorsque vous appelez foo la valeur bar est tout simplement de type Secret, le compilateur ne sait pas d'où vient votre Secret.

Votre valeur bar est juste un Secret, et il ne conserve pas d'informations pointant vers Curry#l[Int].

Le compilateur ne peut pas déduire que P => Curry#l et T => Int.

Le compilateur ne voit que les Secret et perd le contexte Curry#l malgré annoter le type avec Curry#l[Int] au lieu de Secret.

Un autre exemple (en venant de this question), ce qui expose un comportement similaire:

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

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

foo(bar) 

la situation CurryObj est différente, considèrent que CurryInt#l, Curry#l et CurrStatic#l sont simplement des alias de type. CurryObj.l, à la place, est un type réel, une partie de l'objet concret CurryObj.

Jetons un coup d'oeil à ce (REMP):

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] 

Notez que l'alias de type Curry#l[Int] ->Secret est résolu immédiatement, au lieu du type réel CurryObj.l[Int] est maintenu.

+0

type 'Curry' est comme' CurrStatic' de mon exemple. Il ressemble beaucoup à 'CurryObj'. Pourquoi les informations de type sont sauvegardées dans un cas et perdues dans un autre? – ayvango

+0

J'ai mis à jour la réponse pour répondre à votre préoccupation. –

+0

Cela a une signification. Mais dans mon cas 'Curry # l' est utilisé sans lui appliquer' Int'. Et 'Secret' a aussi un paramètre de type, donc il n'a pas pu être éliminé. Comme je l'ai vu dans '-Yinfer-debug', le paramètre type est préservé mais sous une forme inhabituelle – ayvango

0

Il semble que le compilateur scala ne pouvait pas gérer les types nus à partir de projections de type. J'ai tracé -Ytyper-debug sortie et constaté que toutes les informations de type nécessaires est emporté mais est rejetée sans raison apparente. Mais il est toujours possible d'obtenir des expressions enveloppantes de type lambdas à l'intérieur d'un trait. That answer m'a donné un aperçu de la solution.

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]]