Добрый день, все.Как переосмыслить термин DSL в окончательном безбрежном подходе?
Наше приложение использует типизированную DSL для описания определенной бизнес-логики. DSL поставляется с несколькими переводчиками без тегов.
Вот как его условия были объявлены:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE EmptyDataDecls #-}
class Ctl impl where
-- Lift constants.
cnst :: Show t => t -> impl t
-- Obtain the state.
state :: impl (Maybe Int)
-- Test for equality.
eq :: impl Int -> impl Int -> impl Bool
-- If-then-else.
ite :: impl Bool -> impl t -> impl t -> impl t
-- Processing outcomes.
retry :: impl Outcome
finish :: impl Outcome
-- Require a value.
req :: impl (Maybe t) -> impl t
Бизнес-логика затем описывается с помощью фрагментов кода в этом DSL:
proc1 :: Ctl impl => impl Outcome
proc1 = ite (req state `eq` cnst 5) finish retry
Эти определения высокого уровня ставятся использовать с переводчиками. У меня есть текстовый интерпретатор, чтобы получить читаемый текстовое описание того, как определяются бизнес-процессы:
newtype TextE t = TextE { evalText :: String }
instance Ctl TextE where
cnst v = TextE $ show v
state = TextE "My current state"
eq v1 v2 = TextE $ concat [evalText v1, " equals ", evalText v2]
ite cond t e =
TextE $
concat ["If ", evalText cond, ", then ", evalText t, ", else ", evalText e]
retry = TextE "Retry processing"
finish = TextE "Finish"
req v = TextE $ concat ["(", evalText v, ")*"]
переводческой на DSL с TEXTE производит строку:
λ> (evalText proc1) :: String
"If (My current state)* equals 5, then Finish, else Retry processing"
Такое описание используется в качестве эталона для пользователей/аналитиков.
Я также могу оценить термин DSL для метаязыка (Haskell) с другой переводчик, который, как приложение на самом деле следует правила:
newtype HaskellE t = HaskellE { evalHaskell :: HaskellType t }
-- Interface between types of DSL and Haskell.
type family HaskellType t
instance Ctl HaskellE where
cnst v = HaskellE v
state = HaskellE dummyState
eq v1 v2 = HaskellE $ evalHaskell v1 == evalHaskell v2
ite cond t e =
HaskellE $
if (evalHaskell cond)
then (evalHaskell t)
else (evalHaskell e)
retry = HaskellE $ print "Retrying..."
finish = HaskellE $ print "Done!"
req [email protected](HaskellE v) =
case v of
Just v' -> HaskellE v'
Nothing ->
HaskellE (error $
"Could not obtain required value from ") -- ++ evalText term)
-- Dummy implementations so that this post may be evaluated
dummyState = Just 5
type Outcome = IO()
type instance HaskellType t = t
Этот интерпретатор производит работоспособный код Haskell:
λ> (evalHaskell proc1) :: IO()
"Done!"
Теперь к моей проблеме: Я хотел бы использовать интерпретатор TEXTE из HaskellE переводчика. Например, я хочу определить ветвь сбой req
способом, который включает текстовое представление вложенного термина (обычно полученное evalText term
) в сообщении об ошибке. Соответствующий код закомментирован в версии req
для HaskellE выше. Если комментарий вернулся, код выглядит
HaskellE (error $
"Could not obtain required value from " ++ evalText term)
Однако система типа мешает мне это сделать:
tagless.lhs:90:71: Couldn't match expected type ‘TextE t0’ …
with actual type ‘HaskellE (Maybe t)’
Relevant bindings include
v :: HaskellType (Maybe t)
(bound at /home/dzhus/projects/hs-archive/tagless.lhs:85:22)
term :: HaskellE (Maybe t)
(bound at /home/dzhus/projects/hs-archive/tagless.lhs:85:7)
req :: HaskellE (Maybe t) -> HaskellE t
(bound at /home/dzhus/projects/hs-archive/tagless.lhs:85:3)
In the first argument of ‘evalText’, namely ‘term’
In the second argument of ‘(++)’, namely ‘evalText term’
Compilation failed.
сообщение в основном говорит, что интерпретатор HaskellE уже был выбран, когда тип переменной impl
был создан, а I не может использовать TextE-интерпретатор изнутри HaskellE.
То, что я не могу понять, это: как мне переосмыслить термин от HaskellE до TextE?
Если я совершенно неправильно здесь, как я изменить свой подход, так что я могу фактически использовать текстовый интерпретатор из Haskell один без повторного внедрения его в HaskellE? Похоже, что вполне возможно с первоначальным подходом вместо финального.
Я снял свою фактическую DSL и упростил типы и интерпретаторы ради краткости.
(Что такое " «без привязки» в контексте?) – user2864740
@ user2864740 В этой статье объясняется, что это означает; он обсуждает, какие теги находятся в разделе 3.1: http://okmij.org/ftp/tagless-final/course/lecture.pdf –
@DavidYoung Спасибо! – user2864740