簡體   English   中英

如何在 Typeclass Show 中用“a”定義 Monad 實例“ma”?

[英]How to define a Monad instance “m a” with “a” in Typeclass Show?

我想用容器 M 定義一個 monad 實例作為 monad 並且包含的類型a應該是 class Show的成員。 類型系統應確保此約束(即aShow的成員)。

我像這樣嘗試過,但不幸的是M不是正確的類型:

data M = forall a. Show a => M a 

instance Monad M where
 return x = M x

實現這一目標的所有其他嘗試都會遇到以下問題:由於Monad是構造函數 class,我沒有顯式訪問所包含元素的a類型,因此我無法限制它。

有沒有人知道這個沒有定義新的Monad class 的解決方案?

嗯,實際上可以在某種意義上限制類型構造函數的參數,使用 GADT:

data M a where
    M :: (Show a) => a -> M a

不幸的是,這實際上對您沒有幫助。 在某種程度上,它實際上使事情變得更糟,因為沒有約束的Monad實例,根本不可能編寫實例。

如果您查看上面的構造函數類型簽名,它顯然類似於return ——這說明了為什么您正在做的事情根本上是不可能的。 返回的類型是: (Monad m) => a -> ma ,並且像往常一樣,未綁定的類型變量在最外層被隱式地普遍量化,因此您可以將其讀作“對於所有可能的類型a和所有可能的類型m這是Monad的實例,給定 a 類型a值,您可以構造ma類型的值。 這里的“for all”措辭非常直白—— return 的類型不僅僅是使用類型變量,它還積極地斷言必須允許任何類型a

所以,簡而言之,沒有。 沒有辦法做你想做的事,因為標准Monad class明確指定了相反的內容。

您可能無法完全按照您的要求進行操作,但另一種可能性是您的特定 monad 提供一個動作,該動作明確地執行您想要使用Show執行的任何操作。 也就是說,假設您有:

data M a = {- ... -}
instance Monad M where -- notice: no Show constraint
    {- ... -}

然后您可以另外提供一些操作:

report :: Show a => M a -> M a

我想不出用Show很好地使用這種模式,但我知道一個類似的例子,你可能希望使用Ord約束。 設置是您想要創建一個不確定的 monad(如[a] ),但沒有重復項(如Set a )。 刪除重復項需要一些上下文,例如EqOrd ,但我們不能在每次return / >>=操作時都要求這樣做。 因此,我們要求用戶明確標記應合並重復項的點:

newtype Setlike a = Setlike { toList :: [a] }
instance Monad Setlike where
    return x = Setlike [x]
    Setlike xs >>= f = [y | x <- xs, let Setlike ys = f x, y <- ys]

collapse :: Ord a => Setlike a -> Setlike a
collapse = Setlike . Data.Set.toList . Data.Set.fromList . toList

這可以像這樣使用:

valuesOfInterest = collapse $ do
    v1 <- allValues
    v2 <- allValues
    doSomethingInteresting v1 v2

然后,即使v1v2的某些配對碰巧產生相同的感興趣值,該值也只會在結果中出現一次。

您的用例也可能有一些類似的技巧。

不,這是不可能的,盡管很容易解釋。 看看return的類型簽名:

return :: Monad m => a -> m a

簽名不能改變,所以你的 monad 必須接受任何內容類型。 由於類型 class 本身沒有提及內容類型,因此無法對其強制執行約束。

您可以做的一件事是在所有需要它的函數上編寫此約束並刪除全局限制。 如果您可以僅在需要時證明Show約束的存在,系統的健全性仍然得到保證。

這可以通過一些極端的技巧來實現。 有關實現,請參見rmonad package。 但是,這可能不值得。

為什么你需要有a is Show的約束? 在那個時候強制執行 Show 約束會更容易,然后它會在必要時自然傳播。

暫無
暫無

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

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