2014-08-28 25 views
0

跟進this,我有以下類型類:自動推斷出多參數例如

class Monoid m => BuilderS m a where 
    cstr :: String -> a -> m 

class SafeCopy a where 
    putSafe :: a -> m 

BuilderS提供了實例:

import qualified Data.Serialize.Builder as B 

instance Serialize a => BuilderS B.Builder a where 
    cstr _ = B.fromByteString . encode 

instance BuilderS CustomBuilder Int where 
    cstr = ... 

instance BuilderS CustomBuilder String where 
    cstr = ... 

etc. 

我想定義的SafeCopy情況是這樣的:

data Person = Person { name :: String, age :: Int } 

instance SafeCopy Person where 
    putSafe p = cstr "name" (name p) 

但是,在這個特定ic情況下,編譯器無法找到BuilderS m String的實例。我已經試過幾件事情:

  • 將所有原始數據類型來的putSafe約束: putSafe :: (BuilderS m Int, BuilderS m String, ...) => a -> m。這工作,但不可擴展(即,如果我想在未來BuilderS m Vector約束?)
  • 添加mSafeCopy類型參數。
  • 使用自定義總和類型:data SumT m = forall a b. (BuilderS m a, BuilderS m b) => a :+: b,然後有putSafe :: a -> SumT m

不過,我沒有提供足夠的信息給類型系統,所以它可以推遲決定哪個確切的實例BuilderS供以後使用。我錯過了什麼?

+0

(2)[添加m來輸入參數]有什麼問題? – bennofs 2014-08-28 10:30:37

+0

這兩種情況下的'm'都是獨立的。在第二種情況下,'m'是一個自由參數。所以,你應該手動編寫final類型,'putSafe p = cstr「name」(name p):: CustomBuilder String' – viorior 2014-08-28 10:48:20

+2

你的putSafe類型承諾能夠返回調用者想要的任何類型。顯然這是不可能的。 – augustss 2014-08-28 11:47:33

回答

1

你可以做這樣的事情:

class SafeCopy a m where 
    putSafe :: a -> m 

instance BuilderS m String => SafeCopy Person m where 
    putSafe p = cstr "name" (name p) 

你需要打開大量的語言擴展。

+0

完美,謝謝。 – 2014-08-29 12:03:25