gpt4 book ai didi

haskell - 处理可组合的免费 DSL 中的不明确类型

转载 作者:行者123 更新时间:2023-12-02 14:32:41 25 4
gpt4 key购买 nike

我正在构建几个 DSL,它们应该可以基于“免费 monad”和“点菜数据类型”进行组合,使用 freecompdata 包(本质上与 Combining Free types 类似)。

虽然这适用于一些简单的 DSL,但我坚持使用具有类型参数的 DSL,如果构造函数/命令不依赖于此类型参数,则会导致类型参数不明确 GHC 错误。

为了澄清这一点,这里有一些代码:

{-# 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 = _

按照 GHC 的提示,尝试通过启用 AllowAmbigouslyTypes 扩展来实现这一点并没有让我更进一步。我尝试在类型签名中添加一些 forall a 风格的东西,但没有成功。

有什么办法可以让这个模式发挥作用吗?

最佳答案

这是“按菜单点菜”开放金额的一个相对众所周知的限制。

简而言之,如果我们有 f如果仿函数本身具有一个或多个内部类型索引,那么对于包含该仿函数的开放求和,类型推断会受到严重影响。

为了说明原因,假设我们有一个未清总和,其中包含 DSL ()和一个 DSL 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))

或者,如果我们要求只有一个DSL,我们可以恢复良好的类型推断和明确性。在公开总和中。然而,这涉及重写 :<: 的类型级查找代码对于像 DSL 这样的仿函数(那些有内部类型索引的)。我们确实不能用 compdata 来做到这一点就这样,因为它不导出相关的 type-level machinery.

我写了一个minimal example对于您的情况,上面的实现是什么样子的。我不把它贴在这里,因为它有点长而且没有教益。请注意,内部索引的选择完全由仿函数的构造函数和开放和决定。这也修复了其他情况的类型推断;例如,对于旧代码,我们必须对 Write x f 的每次使用进行类型注释如果x是数字文字或多态值,而在新代码中它是被推断出来的。

另请注意,示例实现仅适用于具有单个内部索引的仿函数!如果我们想要一个 DSL a b next ,那么我们也必须为这种情况编写新代码,或者使用 DSL '(a, b) next反而。

关于haskell - 处理可组合的免费 DSL 中的不明确类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30058292/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com