所以我正在尝试做一些新颖的事情(我认为),但我对 Haskell 类型级编程的经验不足,无法自己解决。
我有一个免费的单子,描述了一些要执行的效果(一个 AST,如果这是你滚动的方式),我想根据对预期效果的一些描述来解释它。
到目前为止,这是我的代码::
{-# LANGUAGE DeriveFunctor, FlexibleInstances, GADTs, FlexibleContexts #-}
import Control.Monad.Free -- from package 'free'
data DSL next
= Prompt String (String -> next)
| Display String next
deriving (Show, Functor)
prompt p = liftF (Prompt p id)
display o = liftF (Display o ())
-- |Just to make sure my stuff works interactively
runIO :: (Free DSL a) -> IO a
runIO (Free (Prompt p cont)) = do
putStr p
line <- getLine
runIO (cont line)
runIO (Free (Display o cont)) = do putStrLn o; runIO cont
runIO (Pure x) = return x
这就是“核心”代码。这是一个示例程序:
greet :: (Free DSL ())
greet = do
name <- prompt "Enter your name: "
let greeting = "Why hello there, " ++ name ++ "."
display greeting
friendName <- prompt "And what is your friend's name? "
display ("It's good to meet you too, " ++ friendName ++ ".")
为了测试这个程序,我想使用一个函数runTest :: Free DSL a -> _ -> Maybe a
,它应该像这样模糊地接受一个程序和一些“预期效果”的规范:
expect = (
(Prompt' "Enter your name:", "radix"),
(Display' "Why hello there, radix.", ()),
(Prompt' "And what is your friend's name?", "Bob"),
(Display' "It's good to meet you too, Bob.", ()))
expect
并通过将程序执行的每个效果与列表中的下一项进行匹配来解释程序。然后关联的值(每对中的第二项)应作为该效果的结果返回给程序。如果所有效果都匹配,则程序的最终结果应以Just
. 如果某些内容不匹配,Nothing
则应返回(稍后我将对其进行扩展,使其返回信息丰富的错误消息)。
当然这个expect
元组是没有用的,因为它的类型是一个巨大的东西,我不能写一个通用runTest
函数。我遇到的主要问题是我应该如何表示这个预期意图的序列,以便我可以编写一个函数,该函数适用于任何程序的任何序列Free DSL a
。
- 我隐约知道 Haskell 中的各种高级类型级功能,但我还没有经验知道应该尝试使用哪些东西。
- 我应该为我的
expected
序列使用 HList 或其他东西吗?
非常感谢任何有关事情的提示。