2011-10-03 60 views
5

鑑於這樣的一個或that one簽名:字符串看作是一個Monoid

def foo[A, F[_]](implicit mon: Monoid[F[A]], pr: Pure[F]): F[A] 

假設A爲Char,有沒有辦法讓一個String而不是List[Char]

String不接受類型參數,所以我認爲這是不可能的。下一個最佳選擇是什麼?現在,我對結果使用mkString,但那並不理想。

我覺得String""一個獨異附加+ ...

+0

爲什麼你需要Monoid [F [A]]而不是Monoid [F]? – CheatEx

+0

@CheatEx,在這種情況下,我不是寫'foo'的人,我只是調用者。 – huynhjl

回答

7

說服String可以僞裝成更高級別的類型,從而允許foo形式的函數適用。然而,Scala的類型推斷目前並未達到推斷foo的類型參數的工作,所以你必須明確地提供給他們,

// Assuming the the definitions of Pure and Monoid from Scalaz 

type ConstString = { 
    type λ[X] = String 
} 

implicit def StringPure = new Pure[ConstString#λ] { 
    def pure[A](a: => A) = a.toString 
} 

val sm = implicitly[Monoid[String]] 
val sp = implicitly[Pure[ConstString#λ]] 
val f : String = foo[Char, ConstString#λ](sm, sp) // OK 

注意,Char類型參數foo沒有使用,可以是任何事情,但必須是某種東西:在這種情況下,Char是自然選擇,但NothingAny也可以。

注意,在String的特點該解決方案的行業:所有類型的值轉換爲String其實如此pure[A](a : => A) : String是可實現的所有類型A。爲String以外的類型複製此成語很可能必須利用某種機制來實現pure正文中的類型特定案例(例如,某種模式匹配)。

+2

但是'隱式[Pure [ConstString#λ]]。pure('a')'將返回空字符串,所以這不是很有用。是嗎? –

+0

當然,你需要'Pure [ConstString#λ]'的不同定義來做任何有用的工作。回答編輯以反映這一點。 –

+0

我想我看到了紅隼! –

0

你的分析,Scala的類型系統將拒絕字符串爲不是「高kinded鍵入」 * - > * 是正確的。也就是說,String類型是不能分配給F[_]任何F.你可以嘗試(我沒有檢查這一點)的隱式轉換...

def foo[A, F[_], That](implicit mon: Monoid[F[A]], pr: Pure[F], FA_Is_That: F[A] <%< That) 

...但這不會是有用的我懷疑是因爲您必須在必要時提供您自己的定製轉換,但也因爲性能會很糟糕,假設這是代碼的熱門部分。

或者,使用標準庫,你可以使用CanBuildFrom機器,但它顯然是遠遠如何很好這將與scalaz風格類型類混合。

def foo[A, F[_], That](implicit mon: Monoid[F[A]], pr: Pure[F], b: CanBuildFrom[A, F[A], That]): That 

在該方法的身體,當然,你將需要使用生成器構造返回值,而不是在含半幺羣/純類型類,使它們有些多餘,我懷疑。

6

我能想到的最佳解決方案是定義從List[Char]String的隱式轉換。

相關問題