简体   繁体   English

推断类型不明确

[英]Inferred type is ambiguous

I'm trying to build a library to fill in a template based on some context. 我正在尝试建立一个库来基于某些上下文填充模板。

The relevant data types are a ContextNode and Context . 相关的数据类型是ContextNodeContext

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

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

I defined a typeclass ContextGenerator to be able to derive something context like for data types using generics. 我定义了一个类型类ContextGenerator ,以便能够使用泛型派生某种类似于数据类型的上下文。

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

Context should be an instance of ContextGenerator Context应该是ContextGenerator的实例

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

Some code to make contexts 一些代码来制作上下文

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

The thing that isn't working is when I do the following (in repl where I enabled OverloadedStrings and FlexibleContexts) 不起作用的是当我执行以下操作(在repl中,我启用了OverloadedStrings和FlexibleContexts)

> 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

It seems to me that the GHC infers that the two m 's in the instance definition are different, is that correct? 在我看来,GHC推断实例定义中的两个m是不同的,对吗? How can I tell GHC that these should be the same? 我怎样才能告诉GHC这些应该是相同的?

You can make this work using functional dependencies in GHC - just add the language-extension and rewrite your type-class to: 您可以使用GHC中的功能依赖项来完成这项工作-只需添加语言扩展并将类型类重写为:

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

this basically says that a should include the choice for m (you could say ContextGenerator is now not a binary relation for the types m and a but a function from a -> m - which is implied by the syntax of the extension too) 这基本上说a应该包括对m的选择(您可以说ContextGenerator现在不是类型ma的二进制关系,而是ContextGenerator a -> m的函数,扩展语法也暗含了该函数)

working example: 工作示例:

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

test-session: 测试会议:

λ> 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...)

remark 备注

as those types and classes are dependent of each other I am unsure that you really have a use-case for the type-class here- maybe you would be fine with just the function without all the overhead instead? 因为这些类型和类彼此依赖,所以我不确定您在这里确实有一个类型类用例-也许只使用函数而没有所有开销就可以了吗?

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM