2017-08-11 124 views
15

我使用=:=作爲示例類型lambda來進行簡單的最小示例。如何正確定義lambda類型?

=:=類型有兩個參數,我想在類型級別咖喱一個。

我把幼稚的做法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'會是正確的scala表達式。 – ayvango

3

考慮您的示例的這一簡化版本:

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

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

foo(bar) 

當調用foobar僅僅是類型爲Secret,編譯器不知道您的特定Secret來自何處。

您的bar值只是一個Secret,它不保留指向Curry#l[Int]的信息。

編譯器無法推斷出P => Curry#lT => Int

編譯器只能看到Secret和失去Curry#l背景下,儘管有Curry#l[Int]代替Secret註釋類型。

另一個例子(從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#lCurrStatic#l只是類型別名。相反,CurryObj.l是實際類型,是具體對象CurryObj的一部分。

讓我們一起來看看這個(REPL):

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] 

注意,類型別名Curry#l[Int] - >Secret立即解決,而不是實際的類型CurryObj.l[Int]保持。

+0

類型'Curry'就像我的例子中的'CurrStatic'。它看起來非常相似'CurryObj'。爲什麼類型信息保存在一個案例中並在另一個案例中丟失? – ayvango

+0

我已更新答案以解決您的問題。 –

+0

它有意義。但在我的情況下'Curry#l'被使用時沒有對其應用'Int'。 'Secret'也有類型參數,所以不能被刪除。正如我在'-Yinfer-debug'中看到的那樣,類型參數被保留,但是以一種不尋常的形式 – ayvango

0

似乎scala編譯器無法處理類型投影的裸類型。我追蹤了-Ytyper-debug的輸出,發現所有需要的類型信息都被帶走了,但沒有明顯原因就被拒絕了。但是仍然有可能在特徵中獲得類型lambdas包裝表達式。 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]]