Sve*_*mir 4 polymorphism haskell typeclass rank-n-types
假设我有一个类,它为其成员类型的值声明了一些构造函数:
\nclass C t where\n fromInt :: Int -> t\n fromString :: String -> t\nRun Code Online (Sandbox Code Playgroud)\n进一步假设,我想使用这些多态构造函数创建一堆值并将它们放入Mapfromcontainers包中。但重要的是,我希望这些值保持多态性,并推迟对其具体类型的决定,直到从地图中提取它们为止。
newtype WrapC = WrapC (forall t . C t => t)\n\nnewtype MapC = MapC (Map String WrapC)\nRun Code Online (Sandbox Code Playgroud)\n使用RankNTypes扩展,我可以定义这样一个映射,以下定义见证了确实可以从中提取多态值的事实:
get :: C t => String -> MapC -> Maybe t\nget key (MapC m) = fmap (\\(WrapC t) -> t) $ Map.lookup key m\nRun Code Online (Sandbox Code Playgroud)\n然而,当我想向映射添加一个值时,我遇到了类型错误,因为 Haskell 显然无法统一一些隐藏的类型变量。定义:
\nadd :: C t => String -> t -> MapC -> MapC\nadd key val (MapC m) = MapC $ Map.insert key (WrapC val) m\nRun Code Online (Sandbox Code Playgroud)\n无法编译:
\n\xe2\x80\xa2 Couldn't match expected type \xe2\x80\x98t1\xe2\x80\x99 with actual type \xe2\x80\x98t\xe2\x80\x99\n \xe2\x80\x98t1\xe2\x80\x99 is a rigid type variable bound by\n a type expected by the context:\n forall t1. C t1 => t1\n at src/PolyMap.hs:21:53-55\n \xe2\x80\x98t\xe2\x80\x99 is a rigid type variable bound by\n the type signature for:\n add :: forall t. C t => String -> t -> MapC -> MapC\nRun Code Online (Sandbox Code Playgroud)\n直觉上我猜测这是隐藏在里面的类型变量WrapC无法统一。我不明白的是为什么需要这样。或者我怎样才能让这个例子工作\xe2\x80\xa6
你只需要给你的函数一些实际上多态的东西:
add :: String -> (forall t. C t => t) -> MapC -> MapC
Run Code Online (Sandbox Code Playgroud)
但也许我会提出一些更愚蠢的建议。你能摆脱这个吗?
type MapC = Map String (Either Int String)
get :: C t => String -> MapC -> Maybe t
get k m = either fromInt fromString <$> Map.lookup k m
Run Code Online (Sandbox Code Playgroud)
不需要类型系统扩展。