2016-11-20 95 views
4

我想了解免費單子。所以在教程的幫助下,我寫了一個玩具的例子,現在我不明白它爲什麼編譯。這裏是:爲什麼此代碼與免費的monad解釋器編譯?

import cats.free.Free 
import cats.instances.all._ 
import cats.~> 

trait Operation[+A] 

case class Print(s: String) extends Operation[Unit] 

case class Read() extends Operation[String] 


object Console { 

    def print(s: String): Free[Operation, Unit] = Free.liftF(Print(s)) 

    def read: Free[Operation, String] = Free.liftF(Read()) 

} 

object Interpreter extends (Operation ~> Option) { 
    // why does this compile? 
    override def apply[A](fa: Operation[A]): Option[A] = fa match { 
    case Print(s) => Some(println(s)) 
    case Read() => Some(readLine()) 
    } 
} 

object Main { 
    def main(args: Array[String]) { 
    val program = for { 
     _ <- Console.print("What is your name?") 
     name <- Console.read 
     _ <- Console.print(s"Nice to meet you $name") 
    } yield() 
    program.foldMap(Interpreter) 
    } 
} 

我在說解釋器的應用方法。它應該返回Option [A],但是我可以在這裏返回Option [Unit]和Option [String],所以我認爲它應該是一個編譯錯誤。但事實並非如此。此代碼編譯和工作(儘管Idea告訴我這是一個錯誤)。這是爲什麼?

UPD:但爲什麼不編譯?

def test[A](o: Operation[A]): Option[A] = o match { 
    case Print(s) => Some(s) 
    case Read() => Some(Unit) 
    } 

回答

3

apply方法應該在那裏A由參數的類型確定返回Option[A]。也就是說,如果參數的類型爲Operation[Unit],那麼結果也應該是Option[Unit]等等。

現在你的身體完全符合那份合約。是的,您確實有一種情況,即您返回Option[Unit]而不是一般Option[A],但只有在參數是Print的實例並因此Operation[Unit]時才這樣做。當您的參數是Operation[Unit]時,您只能返回Option[Unit],所以合同不會中斷。 ReadString也是如此。請注意,如果您在Read的情況下返回了Option[Unit],那將是一個錯誤,因爲您現在要返回的參數類型不是參數的類型。

所以這就是爲什麼代碼在語義上是正確的,但它爲什麼編譯?這是因爲Scala類型檢查器(與IntelliJ的近似值不同)足夠智能以在模式匹配時考慮附加類型信息。也就是說,在case Print中,它知道您剛剛匹配Operation[A]類型的值與Operation[Unit]類型的模式,因此它在案例正文中指定A = Unit


關於你提到的更新:

case Print(s) => Some(s) 

在這裏,我們有Operation[Unit]型模式(記住Print擴展Operation[Unit]),所以我們應該得到Option[Unit]類型的結果,但Some(s)具有類型Option[String]。所以這是一種類型不匹配。

case Read() => Some(Unit) 

首先UnitUnit類型的伴侶的對象,所以它有它自己的類型,而不是鍵入Unit。類型Unit的唯一值是()

除此之外,它是與上述相同的情況:該圖案具有類型Operation[String],所以結果應該是Operation[String],不Operation[Unit](或Operation[Unit.type])。

+0

哇,斯卡拉克真的很聰明。謝謝。 –

+0

我已經接受了答案,但你能看看我的更新嗎? –

+0

我的不好,抱歉。它會像你悲傷一樣工作。我刪除了更新。 –

相關問題