[英]Store and retrieve an object of some typeclass - is it possible? If yes, how?
假設我有一些類型類Foo
和一些數據類型FooInst
,它是Foo
實例:
class Foo a where
foo :: a -> String
data FooInst = FooInst String
instance Foo FooInst where
foo (FooInst s) = s
現在,我想定義一種數據類型,它存儲一個類型在Foo
類型類中的對象,並且能夠從該數據類型中提取該對象並使用它。
我找到的唯一方法是使用GADT和Rank2Types語言擴展並定義數據類型,如下所示:
data Container where
Container :: { content :: Foo a => a } -> Container
但問題是,我無法使用content
選擇器從Container中獲取內容:
cont :: Container
cont = Container{content = FooInst "foo"}
main :: IO ()
main = do
let fi = content cont
putStrLn $ foo fi
導致編譯錯誤
Cannot use record selector ‘content’ as a function due to escaped type variables
Probable fix: use pattern-matching syntax instead
但是當我修改let ...
行時
let Conainer fi = cont
我得到一個相當有趣的錯誤
My brain just exploded
I can't handle pattern bindings for existential or GADT data constructors.
Instead, use a case-expression, or do-notation, to unpack the constructor.
如果我再次嘗試修改let ...
行以使用case-expression
let fi = case cont of
Container x -> x
我得到了一個不同的錯誤
Couldn't match expected type ‘t’ with actual type ‘a’
because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor
Container :: forall a. (Foo a => a) -> Container,
in a case alternative
at test.hs:23:14-24
那么, 我如何存儲一個typeclassed的東西並將其取回?
附:
data Container where
Container :: {content :: Foo a => a} -> Container
甚至沒有強制執行類型類約束。 那是
void :: Container
void = Container {content = 42 :: Int}
類型檢查,即使42 :: Int
不是 Foo
的實例。
但如果你改為:
data Container where
Container :: Foo a => {content :: a} -> Container
Rank2Types
語言擴展。 void
示例將不再進行類型檢查。 此外,您可以在具有模式匹配的內容上調用foo
(或具有簽名Foo a => a -> ...
任何其他函數):
case cont of Container {content = a} -> foo a
例如
main :: IO ()
main = do
case cont of
Container fi -> putStrLn $ foo fi
你需要在一個表達式中封裝你對存在類型字段fi
,該表達式的類型不依賴於fi
的類型; 這里putStrLn $ foo fi
,其類型為IO ()
。
這個例子是沒用的,因為你可以對Container
的content
字段做的唯一事情就是調用foo
,所以你也可以在構造容器之前調用foo
並給出字段類型String
。 但是,如果Foo
具有類似a -> a -> a
類型的操作,或者Container
具有涉及相同存在量化變量的類型的多個字段等,則更有趣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.