我试图在运行时从众多实例中选择一个实例。真的是一种Backend
。在运行时选择实例行为
我能够做到这一点,如果我在编译时选择一个实例或其他。
修订大概我想有些类似于Database.Persist(它定义一个完整的行为,但很多情况下:MongoDB中,SQLite的和PostgreSQL,...)。但对我来说太复杂了。
更新使用GADTs
工程,但我认为存在一个更好的方法(完整的代码在底部)。
在一些OOP语言我的问题是或多或少
interface IBehavior { void foo(); }
class AppObject { IBehavior bee; void run(); }
...
var app = new AppObject { bee = makeOneOrOtherBehavior(); }
....
我试过很多方法(和大量的扩展:d),但没有工作。
非正式地,我想定义一个具有特定行为的class
,并将这个通用定义应用到某个应用程序中,然后在运行时选择一个instance
。
通用行为(不是真正的代码)
class Behavior k a where
behavior :: k -> IO()
foo :: k -> a -> Bool
...
(我认为因为每个instance
k
需要可能需要自己的上下文/数据;像其他限制key
/value
可能存在)
两个实例
data BehaviorA
instance Behavior BehaviorA where
behavior _ = print "Behavior A!"
data BehaviorB
instance Behavior BehaviorB where
behavior _ = print "Behavior B!"
我的应用程序使用该行为(这里开始乱)
data WithBehavior =
WithBehavior { foo :: String
, bee :: forall b . Behavior b => b
}
run :: WithBehavior -> IO()
run (WithBehavior {..}) = print foo >> behavior bee
我想在运行时
selectedBee x = case x of
"A" -> makeBehaviorA
"B" -> makeBehaviorB
...
withBehavior x = makeWithBehavior (selectedBee x)
选择,但我失去了进入扩展型的依赖和其他:(
的迷宫,我不能设置正确的类型selectedBee
功能。
任何帮助将不胜感激! :)
(使用GADTs
,但没有额外a
类型参数!)
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE GADTs #-}
import System.Environment
import Control.Applicative
class Behavior k where
behavior' :: k -> IO()
data BehaviorInstance where
BehaviorInstance :: Behavior b => b -> BehaviorInstance
behavior :: BehaviorInstance -> IO()
behavior (BehaviorInstance b) = behavior' b
data BehaviorA = BehaviorA
instance Behavior BehaviorA where
behavior' _ = print "Behavior A!"
makeBehaviorA :: BehaviorInstance
makeBehaviorA = BehaviorInstance BehaviorA
data BehaviorB = BehaviorB
instance Behavior BehaviorB where
behavior' _ = print "Behavior B!"
makeBehaviorB :: BehaviorInstance
makeBehaviorB = BehaviorInstance BehaviorB
data WithBehavior =
WithBehavior { foo :: String
, bee :: BehaviorInstance
}
run :: WithBehavior -> IO()
run (WithBehavior {..}) = print foo >> behavior bee
main = do
n <- head <$> getArgs
let be = case n of
"A" -> makeBehaviorA
_ -> makeBehaviorB
run $ WithBehavior "Foo Message!" be
我认为你最好的选择可能是'reflection'包(不要用'Given'来保存你的理智)。 – dfeuer
我得到'WithBehavior'的类型是'String - > WithBehavior'。 'withBehavior'的类型是什么?什么是'makeWithBehavior'?它最终崩溃了,意图操作落入未定义和未定义的符号。 –
@dfeuer使用'data BehaviorWrapper其中{BehaviorWrapper :: Behavior b => b - > BehaviorWrapper}'可以做,但我想避免类型包装:) – josejuan