2015-02-23 79 views
4

說我有與狀態的狀態單子爲HList和我定義了一個組合子負責這種HList的第一n元素:查找類型的類實例

import scalaz._, Scalaz._ 
import shapeless._, ops.hlist._, Nat._ 

def take[S <: HList](n: Nat)(implicit tk: Take[S, n.N]): 
    IndexedState[S, tk.Out, Unit] = ??? 

for { 
    _ <- init[Int :: String :: HNil] 
    _ <- take(_1) 
    x <- state("abc") 
} yield x 

的在類型推斷期間scala編譯器被卡住了。它並不推斷takeS類型參數是Int :: String :: HNil。因此,編譯器無法找到參數tk的隱含值。

[error] could not find implicit value for parameter tk: shapeless.ops.hlist.Take[S,shapeless.Nat._1.N] 
[error]  _ <- take(_1) 

我知道,我可以通過簡單地暴露狀態或者通過固定S幫助編譯器。但我不想!這種額外的信息似乎是多餘的:

def take[S <: HList](hl: S, n: Nat)(implicit tk: Take[S, n.N]): 
    IndexedState[S, tk.Out, Unit] = ??? 

for { 
    hl <- init[Int :: String :: HNil] 
    _ <- take(hl, _1)   // Redundant 
    _ <- take[Int :: HNil](_1) // Redundant 
    x <- state("abc") 
} yield x 

爲什麼在第一個代碼段,Scala編譯器推斷S作爲Nothing而不是Int :: String :: HNil?我想知道是否可以在不暴露狀態或提供類型信息的情況下獲得此作品?

在此先感謝!

+0

我不認爲編譯器有足夠的信息來推斷'S' - 它所知道的'S'就是在範圍內必須有一個'Take [S,nN]'實例,並且存在一個寬各種不同的'S'。你和我知道期望的返回類型是'IndexedReaderWriterStateT [...,S,...]',但是從那裏到相當複雜的路徑,意識到'S'必須是'take'的類型參數。當您將預期類型展開爲例如'採取(_1):IndexedReaderWriterStateT [...]',這是否得到正確推斷? – lmm 2015-02-23 17:13:10

+0

@Imm - 你確定編譯器沒有足夠的信息來推斷'S'嗎? 'init [Int :: String :: HNil]'給出了一個'IndexedState [Int :: String :: HNil,Int :: String :: HNil,Int :: String :: HNil]'。如果我們遵循這些類型,那麼'flatMap'應該構造一個構造'IndexedState [Int :: String :: HNil,?,?]'的函數。我們給出返回一個IndexedState [S,tk.Out,Unit]的'{_ => take(_1)}'。我認爲兩者之間的匹配應該將'S'修復爲'Int :: String :: HNil'。我在這裏錯過了什麼? – 2015-02-24 12:52:08

回答

0

下編譯:

for { 
    _ <- init[Int :: String :: HNil] flatMap { _ => take(_1) } 
    x <- state("abc") 
} yield x 

你的問題的for -loop大致翻譯成

init[Int :: String :: HNil] flatMap { _ => 
    take(_1) flatMap { _ => 
    state("abc") map { x => 
     x 
    } 
    } 
} 

和scalac似乎不願意推斷take(_1)類型參數給出它已經具有以推斷它下面的一些類型,你直接打電話給flatMap

+0

你知道爲什麼scalac不願意推斷'take(_1)'的類型參數嗎?我不明白爲什麼第一個代碼片段(與序列綜合和flatMap的組合)編譯,而第二個(未加糖的代碼片段)不編譯!這是一個scalac錯誤嗎? – 2015-02-24 13:08:43