Я застреваю, пытаясь выбрать один экземпляр из многих во время выполнения. На самом деле это своего рода Backend
.Выберите поведение экземпляра во время выполнения
Я могу сделать это, если я выбираю один экземпляр во время компиляции.
ОБНОВЛЕНО вероятно я хочу некоторые похожи на Database.Persist (это определение полностью поведение, но много примеров: MongoDB, SQLite, PostgreSQL, ...). Но для меня это слишком сложно.
ОБНОВЛЕНО Использование GADTs
работ, но я думаю, что существует лучший способ (полный код внизу).
В каком-то языке ООП моя проблема более или менее
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
...
(я думаю k
необходимо, так как каждый instance
может понадобиться их собственный контекст/данные, другие ограничения, такие как 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