类型项限制的类型项列表

and*_*opp 15 haskell typeclass heterogeneous

我正在尝试编码一个项目列表,这些项目的类型仅限于某些类型类的实例:

{-# LANGUAGE RankNTypes, TypeSynonymInstances, LiberalTypeSynonyms #-}
module Test where

class Someable a where
  some :: a -> String

data Some = Some String

type SomeGroup = forall a. Someable a => [a]

instance Someable Some where
  some (Some v) = v

instance Someable SomeGroup where
  some (x:xs) = (some x) ++ ", " ++ (some xs)

main = do
  putStrLn $ show.some [Some "A", [Some "B", Some "C"]]
Run Code Online (Sandbox Code Playgroud)

但编译失败并出现错误:

Test.hs:14:10:
    Illegal polymorphic or qualified type: SomeGroup
    In the instance declaration for `Someable SomeGroup'
Run Code Online (Sandbox Code Playgroud)

似乎我甚至没能为类型同义定义实例...

我知道异构集合 wiki文章,但想知道为什么我的方法不起作用 - 我似乎很自然地通过限制集合来定义类型以包含具有类型的项目,这些类型是某种类型的实例.

ham*_*mar 9

如果我理解正确,就需要有一个数据类型包装存在主义,以便有一个存储类型类字典和每个元素的地方.

添加一些包装器使它工作:

{-# LANGUAGE ExistentialQuantification, TypeSynonymInstances #-}

module Test where

class Someable a where
  some :: a -> String

data Some = Some String

data SomeWrapper = forall a. Someable a => SomeWrapper a

type SomeGroup = [SomeWrapper]

instance Someable Some where
  some (Some v) = v

instance Someable SomeWrapper where
  some (SomeWrapper v) = some v

instance Someable SomeGroup where
  some (x:xs) = (some x) ++ ", " ++ (some xs)

main = do
  putStrLn $ some [SomeWrapper (Some "A"), SomeWrapper [SomeWrapper (Some "B"), SomeWrapper (Some "C")]]
Run Code Online (Sandbox Code Playgroud)

当然,这有点难看.不幸的是,我不知道有任何更好的方法.

  • 请注意,您定义的类型与问题中的类型不同:`∀x.C x => [x]`不同于`[∀x.C x => x]`. (2认同)
  • @ user239558:是的,通常字典是单独传递的,但是当你有存在类型时,这会改变.假设您有一个数据类型`data Foo = forall a.Num a => a`,函数`f(Foo x)= Foo(x + fromInteger 1)`.`f`如何知道使用哪个实例?它无法静态确定,因为我们知道实际类型的唯一地方是我们构造`Foo`值时.答案是类型类字典必须添加为`Foo`的额外隐藏字段,在我们模式匹配时可用. (2认同)