给定其body函数,创建一个类型类的实例(或变通方法)

时间:2012-05-08 11:46:22

标签: haskell typeclass

我想有一个State Monad,我会保留一份模式列表。

data State = S { 
      modes :: [Mode]
}

但是,我有两个要求:

  1. 模式需要是一个带类型的参数化。
  2. 模式可以在运行时构建。
  3. 以下是我试图说服GHC的方式:

    尝试1 ,数据类型

    data Mode a = Mode { 
          complF :: String -> IO [String]
          action :: State -> String -> X a
    }
    
    data State a = S { 
          modes :: [Mode a]
    }
    
    initState :: (String -> IO [String]) -> (State -> String -> X a) -> State a
    initState c a = {
          modes = [buildMode c a]
    }
    
    buildMode :: (String -> IO [String]) -> (State -> String -> X a) -> Mode a
    buildMode c a = {
           complF = c
         , action = a
    }
    

    好......但是,这对我没用,因为每个模式都必须在Mode a内的State a类型。这意味着任何Mode StringMode ()都不能在一个国家内共存。

    尝试2 :,输入class

    class Mode a where
           complF :: String -> IO [String] 
           action :: State -> String -> X a
    
    data State = S {
           modes :: (Mode a) => [a]
    }
    

    但是,现在我不知道如何在complFaction的运行时间内构建模式。似乎必须在编译时定义类型类的实例。

    instance Mode DefaultMode where
           complF :: .. 
           action :: ..
    

    有解决方法吗?

1 个答案:

答案 0 :(得分:4)

如果模式支持固定API,则可以使用existential type隐藏其表示类型。 E.g。

data State = S { 
  modes :: forall a . ModeLike a => [Mode a]
}

然后实现只有ModeLike类型支持的操作的类Mode。你的第二次尝试接近于此。

由于类型类实例已打开,因此您无需更改代码即可添加新实例。

但是,如果您有一个完全动态的系统 - 即您无法枚举可能的模式类型 - 您将不得不使用动态类型作为其中一个实例。