haskell - Hint.interpret 用于 Polysemy.Sem 值时会出现编译器错误
问题描述
我正在尝试使用提示( Language.Haskell.Interpreter)在运行时编译Polysemy monad 值。
当我尝试这样做时,我可靠地得到一个关于:
在“交互式”代码中不当使用运算符的错误;似乎传递给 GHC 的文本提示中有语法错误。
{-# LANGUAGE DataKinds #-}
module Main where
import Polysemy (Embed, embed, runM, Sem)
import Language.Haskell.Interpreter (as, interpret, Interpreter, runInterpreter, setImportsQ)
import Data.Typeable (typeOf)
import Control.Monad.IO.Class (liftIO)
main :: IO ()
main = do
-- Hint works fine to interpret a String:
m <- interpretWithErrors exampleHint
print m
-- And Sem works fine:
runM exampleSem
-- But notice the weird detected type:
print $ typeOf exampleSem
-- And now Hint fails to interpret a Sem:
s <- interpretWithErrors exampleBoth
print $ typeOf s
runM s
type MyEffect = Sem '[Embed IO] ()
exampleSem :: MyEffect
exampleSem = embed $ print "Successful Sem!"
exampleHint :: Interpreter String
exampleHint = do
setImportsQ [("Prelude", Nothing)]
interpret "\"Successful Hint!\"" (as :: String)
exampleBoth :: Interpreter MyEffect
exampleBoth = do
setImportsQ [("Prelude", Nothing), ("Polysemy", Nothing)]
liftIO $ print "Successfully imported!"
-- This is where it fails:
s <- interpret "embed $ print \"Success!\"" (as :: MyEffect)
liftIO $ print "Successfully interpreted!"
return s
interpretWithErrors :: Interpreter a -> IO a
interpretWithErrors i_a = do
e_e_a <- runInterpreter i_a
either (ioError . userError . show) (return) e_e_a
运行上面的打印:
"Successful Hint!"
"Successful Sem!"
Sem (': ((* -> *) -> * -> *) (Embed IO) ('[] ((* -> *) -> * -> *))) ()
"Successfully imported!"
Hint-Polysemy: user error (WontCompile [GhcError {errMsg = "<interactive>:3:41: error: Operator applied to too few arguments: :"}])
一些注意事项:
- 我正在使用 cabal,为了
import
在解释器 monad 中传递该行,我必须从 cabal 沙盒外壳中运行它,因为 Polysemy 没有安装到我的机器上。 - 也就是说,我不认为 cabal 或进口 Polysemy 是问题。如果我只是忽略导入 Polysemy 而只是
setImportsQ [("Prelude", Nothing)]
. - 我正在解释的字符串甚至不需要是一个有效的表达式;我可以在不更改错误的情况下将乱码放在那里。这向我表明问题出在
(as :: MyEffect)
. - 我包括
typeOf
证明那MyEffect
是事实Typeable
。 - 我不知道为什么
typeOf exampleSem
要给出如此长而奇怪的类型签名。我确实认为这在某种程度上是问题所在。重新排列MyEffect
到type MyEffect = Sem ((Embed IO) : []) ()
没有效果。
如果我做错了什么,任何人都清楚吗?我应该如何尝试调试这个问题?假设这是Type.Reflection.Typeable
中的提示、多义或(不太可能)中的错误,我下一步将如何尝试修复它?我想我必须以某种方式确定哪个库有问题?
这是对先前问题的改进。这是原文。
解决方案
不是答案,但我发现了一些您可能会觉得有帮助的发现。
我认为这可能': x xs
是无效的 Haskell 的虚假前缀类型运算符语法(您必须将其编写为中缀或使用(':)
)。所以我实现了一个SemWorkaround
包装模块,它使用Cons
而Nil
不是标准列表语法。似乎与更详细的错误消息(嗯)几乎相同的问题。
然后我认为这可能是显式类型的应用程序,因为错误消息一直在谈论被给予太多参数的事情。所以我尝试将类型级别的列表表示更改为我们过去使用的方式。
{-# LANGUAGE DataKinds, TypeOperators, TypeFamilies #-}
module SemWorkaround where
import Polysemy (Sem, Embed)
import Data.Kind (Type)
data Nil
data Cons (a :: (Type -> Type) -> Type -> Type) (as :: Type)
type family ListToList xs where
ListToList Nil = '[]
ListToList (Cons x xs) = x ': ListToList xs
newtype Sem' l a = Sem' { getSem' :: Sem (ListToList l) a }
并用于Sem'
编组提示边界。例如
type MyEffect' = Sem' (Cons (Embed IO) Nil) ()
...
s <- interpret "Sem' . embed $ print \"Success\"" (as :: MyEffect')
pure $ getSem' s
这行得通。因此,似乎生成该类型的人正在为多态提升构造函数发出显式类型参数,但消费者期望它是隐式的。为了确认我将解决方法模块更改为使用单态数据类型List
。
data List
= Nil
| Cons ((Type -> Type) -> Type -> Type) List
这又奏效了。
最后,我测试了中缀问题,以确保将其更改为:
data List
= Nil
| ((Type -> Type) -> Type -> Type) ::: List
令我惊讶的是,您熟悉的错误消息失败Operator applied to too few arguments
了。因此,您似乎发现了两个错误。有些人不理解应该理解的多类,有些人不理解应该理解的类型运算符。我还没有深入到找出谁错了。
推荐阅读
- mybatis - Mybatis resultMap中如何使用Multiple collection
- linux - 文件未排序后排序
- java - 从数据库加载 netflix zuul 路由值
- python - Gstreamer、Docker、udpsrc、OpenCV、Python... 不工作
- laravel - Laravel 日志异常
- vba - VBA - 如果单元格值更改,则移动行
- javascript - 使用 sequelize 获取字段中具有唯一值的所有行
- javascript - 检查并匹配文件扩展名
- flutter - Flutter:如何在不使用标签栏视图的情况下使用导航器创建标签栏?
- gitlab - 在 GitLab 中更改导航主题颜色