Haskell 在可组合的自由DSL中处理不明确的类型
我正在构建两个DSL,它们应该基于“免费单子”和“按单点数据类型”进行组合,使用免费和compdata包(精神上类似于) 虽然这适用于一些简单的DSL,但我还是停留在一个具有类型参数的DSL上,在构造函数/命令不依赖于此类型参数的情况下,这会导致GHC产生不明确的类型参数错误 为了澄清,这里有一些代码:Haskell 在可组合的自由DSL中处理不明确的类型,haskell,free-monad,Haskell,Free Monad,我正在构建两个DSL,它们应该基于“免费单子”和“按单点数据类型”进行组合,使用免费和compdata包(精神上类似于) 虽然这适用于一些简单的DSL,但我还是停留在一个具有类型参数的DSL上,在构造函数/命令不依赖于此类型参数的情况下,这会导致GHC产生不明确的类型参数错误 为了澄清,这里有一些代码: {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}
module DSL where
import Data.Comp
import Control.Monad.Free
type Index = Int
data DSL a next = Read Index (a -> next)
| Write a (Index -> next)
| GetLastIndex (Index -> next)
deriving (Functor)
read :: (Functor f, DSL a :<: f, MonadFree f m) => Index -> m a
read idx = liftF (inj (Read idx id))
write :: (Functor f, DSL a :<: f, MonadFree f m) => a -> m Index
write a = liftF (inj (Write a id))
-- This works
getLastIndex' :: MonadFree (DSL a) m => m Index
getLastIndex' = liftF (GetLastIndex id)
-- This doesn't:
--
-- Could not deduce (Data.Comp.Ops.Subsume
-- (compdata-0.10:Data.Comp.SubsumeCommon.ComprEmb
-- (Data.Comp.Ops.Elem (DSL a0) f))
-- (DSL a0)
-- f)
-- from the context (Functor f, DSL a :<: f, MonadFree f m)
-- bound by the type signature for
-- getLastIndex :: (Functor f, DSL a :<: f, MonadFree f m) => m Index
-- at simple.hs:30:17-66
-- The type variable ‘a0’ is ambiguous
-- In the ambiguity check for the type signature for ‘getLastIndex’:
-- getLastIndex :: forall (m :: * -> *) (f :: * -> *) a.
-- (Functor f, DSL a :<: f, MonadFree f m) =>
-- m Index
-- To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
-- In the type signature for ‘getLastIndex’:
-- getLastIndex :: (Functor f, DSL a :<: f, MonadFree f m) => m Index
getLastIndex :: (Functor f, DSL a :<: f, MonadFree f m) => m Index
-- getLastIndex = liftF (inj (GetLastIndex id))
getLastIndex = _
{-#语言派生函子#-}
{-#语言灵活语境#-}
{-#语言类型运算符{-}
模块DSL在哪里
导入数据.Comp
进口管制,不含单子
类型索引=Int
数据DSL a next=读取索引(a->next)
|写一个(索引->下一步)
|GetLastIndex(索引->下一步)
派生(函子)
阅读::(函子f,DSL a:索引->MA
读取idx=liftF(inj(读取idx id))
写入::(函子f,DSL a:a->m索引
写入a=liftF(inj(写入id))
--这很有效
getLastIndex':MonadFree(DSL a)m=>m索引
getLastIndex'=liftF(getLastIndex id)
--这并不是:
--
--无法推断(Data.Comp.Ops.Subsume)
--(compdata-0.10:Data.Comp.SubsumeCommon.compemb
--(Data.Comp.Ops.Elem(DSL a0)f)
--(DSL a0)
--(f)
--从上下文(函子f,DSL a:*)(f::*->*)a。
--(函子f,DSL a:
--m指数
--要延迟歧义检查以使用站点,请启用AllowAmbigUstypes
--在“getLastIndex”的类型签名中:
--getLastIndex::(函子f,DSL a:m索引
getLastIndex::(函子f,DSL a:m索引
--getLastIndex=liftF(inj(getLastIndex id))
getLastIndex=_
正如GHC所暗示的那样,试图通过启用AllowAmbigUstypes扩展来实现这一点并没有让我得到任何进一步的帮助。我尝试在类型签名中添加一些关于所有a样式的内容,但没有成功
有什么办法可以让这种模式发挥作用吗?这是一个相对著名的开放式和“点菜式”限制 简言之,如果我们有一个本身有一个或多个内部类型索引的
f
函子,那么对于包含该函子的开和,类型推断会受到很大影响
为了说明原因,假设我们有一个包含DSL()
和aDSL Int
。GHC必须为其中一个选择一个实例,但使用getLastIndex
是不可能的,因为a
参数在参数或返回类型中没有提及。GHC从上下文中基本上没有关于a
的信息
这可以通过使用Data.Proxy以一种有点笨拙的方式进行补救:
import Data.Proxy
getLastIndex ::
forall a f m.
(Functor f, DSL a :<: f, MonadFree f m)
=> Proxy a -> m Index
getLastIndex _ = liftF (inj (GetLastIndex id :: DSL a Index))
import Data.Proxy
getLastIndex::
对于所有a f m。
(函子f,DSL a:代理a->m索引
getLastIndex_u2;=liftF(inj(getLastIndex id::DSL a索引))
或者,如果我们要求开和中只有一个DSL
,我们可以恢复良好的类型推断和明确性
涉及重写<代码>的类型级查找代码:我刚刚发现这正是Haskell所抱怨的,但是你的答案比我写的关于这个主题的两段要令人满意得多。令人敬畏地说,干杯。感谢你的彻底回答!解释为什么“DSL a”无法解决的部分是有意义的,一个d需要“某些”DSL层也有意义,但现在我无法使用示例代码定义“读”或“写”…@NicolasTrangez我编辑了我的链接示例。现在可以在那里找到read
和write
。我们在类型中使用IxOf DSL f
而不是a
参数。