透明地实现特定形式的动态类型

时间:2012-04-02 16:26:28

标签: haskell dynamic types

基本思想是我有一系列函数可以处理来自特定类的任何类型,但在运行时,程序应该读取配置文件并提取类中其中一种类型的元素。 / p>

例如,我有一个'Coefficient'类,它的各种实例,以及与该类类型多态的各种类型的函数;在运行时,将确定并传递该类的一种特定类型。


我不确定如何妥善解决这个问题;我尝试制作'复合'类型,做类似的事情:

data CompoundCoeff = CompoundInt Int | CompoundDouble Double | ...

其中Int,Double,...是“Coefficient”类的实例 然而,它开始成为一项重大努力,以适应代码中涉及的所有函数来使用这些复合类型(并且它也不是一个很好的解决方案,真的)。如果所有函数都具有相同的简单类型,例如

,那就没关系了
Coefficient a => a -> (stuff not involving a anymore)

但遗憾的是并非如此。

我遇到的另一个问题是,我正在使用类型系列,并且有类似

的内容
class (Monoid (ColourData c), Coordinate (InputData c)) => ColourScheme c where
    type ColourData c :: *
    type InputData c  :: *
    colouriseData     :: c -> (ColourData c) -> AlphaColour Double
    processInput      :: c -> InputData c -> ColourData c

如果我必须使用某种复合ColourData数据类型(如前一个),那么这不会干净利落;特别是我不能再保证数据流给出一致的类型(而不仅仅是复合类型的不同'子类型),并且如果我组成了一个,那么(除其他外)必须构成一个虚假的Monoid实例复合ColourData类型。

我也研究过Data.Dynamic,但我再也看不出它如何正确解决问题;似乎出现了完全相同的问题(好吧,甚至稍微差一些,因为我理解只有一个'通用'动态类型。)


问题:如何实现从属于特定类的动态数据类型,而不必重写涉及这些数据类型的所有函数?如果我不必牺牲任何类型的安全性,那将是最好的,但我不是太乐观 程序应该在运行时读取配置文件,并且应用相关类的所有必需函数(多态)。

2 个答案:

答案 0 :(得分:7)

提供一个保证它是类型类Foo的实例但不提供额外保证的对象的传统方法是这样的:

 {-# LANGUAGE ExistentialTypes #-}
 data SomeFoo = forall a . Foo a => SomeFoo a

 instance Foo SomeFoo where
   -- all operations just unwrap the SomeFoo straightforwardly

或者,使用GADT,可能更具可读性......

 data SomeFoo where
   SomeFoo :: Foo a => a -> SomeFoo

答案 1 :(得分:6)

一个建议是编写一个顶级函数,在您选择类型后执行所有最后润色:

topLevel :: SomeTypeClass a => a -> IO ()

然后您的程序可以这样编写:

main = do
    config <- readConfig
    case config of
        UseDouble n -> topLevel n
        UseSymbolic x -> topLevel x
        UseWidgetFrobnosticator wf -> topLevel wf