【问题标题】:Inferred type is ambiguous推断类型不明确
【发布时间】:2015-05-19 17:01:39
【问题描述】:

我正在尝试构建一个库以根据某些上下文填充模板。

相关数据类型为ContextNodeContext

data ContextNode m = ContextText Text
                   | ContextSub (Context m)

type Context m = (Text -> m (Maybe (ContextNode m)))

我定义了一个类型类ContextGenerator,以便能够使用泛型派生一些上下文,例如数据类型。

class ContextGenerator m a where
    clookup :: a -> Text -> m (Maybe (ContextNode m))

Context 应该是ContextGenerator 的一个实例

instance (MonadIO m) => ContextGenerator m (Context m) where
    clookup a s = a s

创建上下文的一些代码

mkContext :: MonadIO m => Text -> ContextNode m -> Context m
mkContext s n = \s' -> if s' == s then return (Just n) else return Nothing

当我执行以下操作时不起作用(在我启用 OverloadedStrings 和 FlexibleContexts 的 repl 中)

> let ctx = mkContext "hello" (ContextText "world")

> clookup ctx "hello"

Could not deduce (Control.Monad.IO.Class.MonadIO m0)
from the context (Control.Monad.IO.Class.MonadIO m1,
                  ContextGenerator m (Context m1))
  bound by the inferred type for ‘it’:
             (Control.Monad.IO.Class.MonadIO m1,
              ContextGenerator m (Context m1)) =>
             m (Maybe (ContextNode m))
  at <interactive>:18:1-19
The type variable ‘m0’ is ambiguous
When checking that ‘it’ has the inferred type
  it :: forall (m :: * -> *) (m1 :: * -> *).
        (Control.Monad.IO.Class.MonadIO m1,
         ContextGenerator m (Context m1)) =>
        m (Maybe (ContextNode m))
Probable cause: the inferred type is ambiguous

在我看来,GHC 推断实例定义中的两个m 是不同的,对吗?我如何告诉 GHC 这些应该是一样的?

【问题讨论】:

  • 我认为最简单的方法可能是将functional dependencies 用于您的ContextGenerator,例如class ContextGenerator m a | a -&gt; m where ...

标签: haskell


【解决方案1】:

您可以在 GHC 中使用 functional dependencies 来完成这项工作 - 只需添加语言扩展并将您的类型类重写为:

class ContextGenerator m a | a -> m where ...

这基本上是说a 应该包括m 的选择(你可以说ContextGenerator 现在不是ma 类型的二元关系,而是来自a -&gt; m 的函数-也被扩展的语法暗示)

工作示例:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}

import Data.Text
import Control.Monad.IO.Class

data ContextNode m = ContextText Text
                   | ContextSub (Context m)

type Context m = (Text -> m (Maybe (ContextNode m)))

class ContextGenerator m a | a -> m where
  clookup :: a -> Text -> m (Maybe (ContextNode m))

instance (MonadIO m) => ContextGenerator m (Context m) where
  clookup a s = a s

mkContext :: MonadIO m => Text -> ContextNode m -> Context m
mkContext s n = \s' -> if s' == s then return (Just n) else return Nothing

测试会话:

λ> let ctx = mkContext "hello" (ContextText "world")

λ> (Just (ContextText t)) <- clookup ctx "hello"

λ> t
"world"

λ> Just _ <- clookup ctx "???"
*** Exception: user error (Pattern match failure in do expression at <interactive>:41:1-6)

λ> Nothing <- clookup ctx "???"
(...empty of course...)

备注

由于这些类型和类相互依赖,我不确定您是否真的有一个类型类的用例 - 也许您可以只使用函数而不需要所有开销?

{-# LANGUAGE OverloadedStrings #-}

import Data.Text
import Control.Monad.IO.Class

clookup :: Context m -> Text -> m (Maybe (ContextNode m))
clookup a s = a s

data ContextNode m
  = ContextText Text
  | ContextSub (Context m)

type Context m = (Text -> m (Maybe (ContextNode m)))

mkContext :: MonadIO m => Text -> ContextNode m -> Context m
mkContext s n = \s' -> if s' == s then return (Just n) else return Nothing

【讨论】:

  • 谢谢,这确实是我需要的。我似乎从未停止在 Haskell 中学习新事物!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 2015-06-23
  • 2018-06-04
  • 2020-05-03
  • 2012-03-13
  • 2021-02-11
  • 1970-01-01
相关资源
最近更新 更多