关于如何从Haskell Wiki编译中创建闭合类型族示例的任何指针?
GHC/AdvancedOverlap(解决方案3)
这是我试过的版本:
{-# LANGUAGE
DataKinds,
FlexibleInstances,
MultiParamTypeClasses,
TypeFamilies,
UndecidableInstances #-}
data HTrue
data HFalse
type family ShowPred a where
ShowPred Int = HTrue
ShowPred Bool = HTrue
ShowPred [a] = ShowPred a
ShowPred a = HFalse
class Print a where
print :: a -> IO ()
instance (ShowPred a ~ flag, Print' flag a) => Print a where
print = print' (undefined :: flag)
class Print' flag a where
print' :: flag -> a -> IO ()
instance Show a => Print' HTrue a where
print' _ x = putStrLn (show x)
instance Print' flag a where
print' _ _ = putStrLn "No show method"
然而,这仍然让我:
Print'重叠的实例flag0 a。
(GHC 8.0.1是我正在使用的版本。)
修改:将第二个实例定义为Print' HFalse a
会导致:
无法推断(Print' flag0 a)因使用print'从上下文:( ShowPred a~flag,Print' flag a)。
编辑:以下是所有更正的示例。所有功劳都归功于@dfeuer。
{-# LANGUAGE
DataKinds,
FlexibleInstances,
MultiParamTypeClasses,
ScopedTypeVariables,
TypeFamilies,
UndecidableInstances #-}
import Prelude hiding (print)
import Data.Proxy
data HTrue
data HFalse
type family ShowPred a where
ShowPred Int = HTrue
ShowPred Bool = HTrue
ShowPred [a] = ShowPred a
ShowPred a = HFalse
class Print a where
print :: a -> IO ()
instance (ShowPred a ~ flag, Print' flag a) => Print a where
print = print' (Proxy :: Proxy flag)
class Print' flag a where
print' :: Proxy flag -> a -> IO ()
instance Show a => Print' HTrue a where
print' _ x = putStrLn (show x)
instance Print' HFalse a where
print' _ _ = putStrLn "No show method"
答案 0 :(得分:1)
初始错误是由
引起的instance Show a => Print' HTrue a where
print' _ x = putStrLn (show x)
instance Print' flag a where
print' _ _ = putStrLn "No show method"
flag ~ HTrue
时这些实例重叠。解决方法是用
instance Print' HFalse a where ...
你的下一个问题是
instance (ShowPred a ~ flag, Print' flag a) => Print a where
print = print' (undefined :: flag)
默认情况下,实例上下文中的flag
变量不在实例主体的范围内,因此undefined :: flag
具有不明确的类型。解决方案是启用ScopedTypeVariables
。
我的最后一点是,不要让print'
获取flag
类型的值然后传递undefined
,而应该使用
print' :: proxy flag -> a -> IO ()
然后导入Data.Proxy
以定义
print = print' (Proxy :: Proxy flag)
现代代理传递方法似乎很新,虽然不太令人满意的版本已经存在了一段时间。有关历史背景,请参阅this question的答案。