簡體   English   中英

強制類型參數為特征

[英]Force type parameter to be a trait

我有以下代碼;

object main
{
    def main(args: Array[String]): Unit = 
    {
        trait E
        {
            def test(): Unit = println("test :)")
        }

        class B[T](val x: Int) 
        {
            def inc(): B[T] with T = new B[T](x + 1) with T
        }

        class A[T](f : B[T] with T => Unit)
        {
            def apply(b: B[T] with T) = f(b)
        }

        val b = new B[E](0) with E
        val a = new A[E](b => b.test())(b)
    }
}

但是, def inc(): B[T] with T = new B[T](x + 1) with T的行def inc(): B[T] with T = new B[T](x + 1) with T不能編譯,給出“需要類類型但是找到T類”和“T需要”的錯誤混合的特質“。 我明白為什么會這樣,但我找不到辦法解決它! 我還沒有找到一種方法來限制T成為一種特質,這讓我擔心這種方法不起作用......

為了給出更多關於我為什么要實現這個目標的背景(只是任何人都可以提供更好的解決方案)我有一個Parsec[S, U, E, A]類,它由接受State[S, U, E] with E的函數構成State[S, U, E] with E對象。 這個想法是U是用戶給定的狀態, A是解析器的結果, S是令牌流, E是狀態的某種擴展(例如,人們可能希望創建Parsec[Stream[String, Char], Int, IndentationSensitive, List[Expr]] U = Int將是用戶想要計數的東西,並且不需要干擾壓痕靈敏度所需的狀態(這是兩個Ints) Parsec[Stream[String, Char], Int, IndentationSensitive, List[Expr]]等等。這將通過混合IndentationSensitive特性提供。然后,如果用戶想要一些其他功能,他們可以繼續混合解析器的更多特征。

那么,無論如何我可以約束代碼中的類型參數T ,這樣我就可以將它混合成B ,或者如果沒有,是否有更好的方法來完成我需要的東西?

如果真的不清楚什么,我試圖完成,然后對代碼審查問題的說明(在很多更詳細)的情況。 但是Parsec[S <: Stream[_, _], U, A]Parsec[S <: Stream[_, _], U, E, A]取代,而State和所有其他部分則相同。

為了給出更多關於我為什么要實現這個目標的背景(只是任何人都可以提供更好的解決方案)我有一個Parsec[S, U, E, A]類,它由接受State[S, U, E] with E的函數構成State[S, U, E] with E對象。 這個想法是U是用戶給定的狀態,A是解析器的結果,S是令牌流,E是狀態的某種擴展(例如,人們可能希望創建Parsec[Stream[String, Char], Int, IndentationSensitive, List[Expr]]

在這種情況下,我只需添加一個val extension: E領域的State和轉變職能,接受State[S, U, E] 如果你真的想要,你可以添加從State[S, U, E]E的隱式轉換,這樣函數可以直接訪問E的成員,但我可能不會自己做。

我已經設法找到問題的解決方案,它並不理想,但它確實解決了系統的其他幾個問題。 也就是說,當我們創建了一個new State[S, U, E](input, pos, state) with E指的是什么與添加的變量發生E 他們迷路了,這是一個殺手。

讓我們定義一個新的類型type StateBuilder[S <: Stream[_, _], U, E] = (Option[State[S, U, E] with E], S, SourcePos, U) => State[S, U, E] with E 這個函數可以構造一個我們想要的新狀態,給定一個可能的先前狀態和一些狀態的“正常”參數的新值。

現在我們可以將國家重新定義為;

case class State[S <: Stream[_, _], U, E](stateInput: S, statePos: SourcePos, stateUser: U, build: StateBuilder[S, U, E])

現在我們只需要一些StateBuilder[S, U, E] ,它們將在狀態之間傳遞,但我們需要在創建初始狀態時將其輸入。 這很好,但這意味着用戶需要了解它們是什么(這有點不利)。 沒有擴展的示例構建器;

trait Default
object Default
{
    def build[S <: Stream[_, _], U](s: Option[State[S, U, Default] with Default], ts: S, pos: SourcePos, u: U): State[S, U, Default] with Default =
    {
        new State[S, U, Default](ts, pos, u, build) with Default
    }
}

一個更復雜的可能是;

trait IndentationSensitive
{
    var stateLevel: Int = 0
    var stateRequiredIndent: Int = 0
}
object IndentationSensitive
{    
    def build[S <: Stream[_, _], U](s: Option[State[S, U, IndentationSensitive] with IndentationSensitive], ts: S, pos: SourcePos, u: U): State[S, U, IndentationSensitive] with IndentationSensitive =
    {
        val s_ = new State[S, U, IndentationSensitive](ts, pos, u, build) with IndentationSensitive
        s match
        {
            case Some(s) => 
                s_.stateLevel = s.stateLevel
                s_.stateRequiredIndent = s.stateRequiredIndent
            case None => 
                s_.stateLevel = 0
                s_.stateRequiredIndent = 0
        }
        s_
    }
}

為了組成擴展,用戶需要手工構建構建器功能,但任何人都無法理解如何操作並不是不合理的。 能夠為每種類型自動構建這些都會很好,但這是一個不同的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM