我希望创建一个关联类型族的两个实例,就像这样。当然,这不会编译,我最终在代码中采用了不同的方法。不过,我仍然对这个用例感到好奇。我认为理论上编译器可以允许这样做。即使有多个put
和get
的实例可供选择,结果类型也会清除需要哪个实例。两种不同方式的类型类的实例
{-# LANGUAGE TypeFamilies #-}
import Data.Word
class Genetic g where
type Sequence g :: *
-- | Writes a gene to a sequence.
put :: Sequence g -> g -> Sequence g
-- | Reads the next gene in a sequence.
get :: Sequence g -> (g, Sequence g)
data SampleGene = Variant1 | Variant2 deriving Show
instance Genetic SampleGene where
type Sequence SampleGene = [Bool]
put xs Variant1 = True : xs
put xs Variant2 = False : xs
get (True:xs) = (Variant1, xs)
get (False:xs) = (Variant2, xs)
instance Genetic SampleGene where
type Sequence SampleGene = [Word8]
put xs Variant1 = 0 : xs
put xs Variant2 = 1 : xs
get (0:xs) = (Variant1, xs)
get (1:xs) = (Variant2, xs)
get _ = error "coding error"
main = do
putStrLn "Working with Bool sequences"
let xs = put [] Variant1 :: [Bool]
let (g,ys) = get xs :: (SampleGene, [Bool])
putStrLn $ "Read " ++ show g
putStrLn "Working with Bool sequences"
let xs = put [] Variant1 :: [Word8]
let (g,ys) = get xs :: (SampleGene, [Word8])
putStrLn $ "Read " ++ show g
我的问题是:
有没有办法在Haskell做到这一点? (除了newtype包装 - 我希望我的库的用户能够直接使用Haskell基本类型。)
如果不是,为什么不呢?也就是说,我违反了什么规则,或者我打了什么类型系统的限制?我想在我正在写的一篇论文中解释这一点,但我试图了解类型系统如何在隐藏条件下工作。因此,如果您在答案中使用技术术语,那么我可以在阅读中了解这些术语。
理论上,未来的Haskell扩展可能允许这样做,还是它是非启动器?
我看过In Haskell, is there any way to express that a type should be an instance of a typeclass in more than one way?,这与我的问题非常相似。但是,我的重点是试图更好地理解类型系统。
我不是100%肯定,但我认为即使有型的家庭,你会需要使用newtypes,这主要是'newtype'语义的用途,另一个用途是你可以使类型更明显,比如使用'Network.Socket.PortNumber'而不是'Word16',使得类型签名更加清晰至于这个论点需要什么。 – bheklilr
您是否曾尝试将“Sequence”的类型作为第二个参数添加到类中? –
@Joachim我没有尝试多参数类型的类。这种趋势似乎是使用类型家庭,但也许这是MPTC可以做某些类型家庭无法做到的事情。 – mhwombat