【问题标题】:Choose default instance under ambiguous types在不明确的类型下选择默认实例
【发布时间】:2016-05-04 02:46:56
【问题描述】:

类型类方法是否有 Haskell 语言扩展来“使用唯一可用的潜在实例”?

我要编译如下

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances     #-}

class Foo a r where
 foo :: a -> r 


instance Foo a (Bool -> a) where
  foo x _ = x 

-- This compiles 
-- bar :: Int -> Bool

-- This does not  
bar :: a -> Bool  
bar _ = True 


use :: Bool 
use = bar $ foo _5 True
  where
    _5 :: Int 
    _5 = 5 

现在我收到以下错误:

     No instance for (Foo Int (Bool -> r0))
  (maybe you haven't applied enough arguments to a function?)
  arising from a use of ‘foo’
The type variable ‘r0’ is ambiguous
Note: there is a potential instance available:
  instance Foo a (Bool -> a) -- Defined at tests/pos/Fixme.hs:9:10

但是由于只有一个潜在的实例可用,有没有办法强制 ghc 使用该实例?或者当类型不明确时,有没有办法将某个实例声明为默认实例?

【问题讨论】:

  • 这个 typeclass + 实例让我畏缩。你确定你在这里表达的是正确的吗?

标签: haskell


【解决方案1】:

标准技巧是让您的实例更具多态性,因此:

instance (a ~ b, bool ~ Bool) => Foo a (bool -> b) where
    foo x _ = x

这使您无法编写其他函数实例,但可以明确在需要函数实例时使用哪些类型。您需要打开 TypeFamilies 扩展来执行此操作。在您的特定情况下,您也许可以只使用instance a ~ b => Foo a (Bool -> b),这将允许更多具有其他参数类型的函数实例,但会出现更频繁的歧义错误。

有关此技巧的更多说明,请参阅a previous answer of mine

【讨论】:

  • 谢谢丹尼尔!我可以保留Bool 原样!以下就够了! instance (a~b) => Foo a (Bool -> b) where foo x _ = x
  • 我试图理解为什么这个技巧有效:是不是因为实例是如此普遍,首先实例被类型检查器“接受”,然后然后约束@ 987654327@被查了吗?在我最初的示例中,是什么阻止了 r 被实例化为 Int
  • @Niki 正确:选择实例时会忽略实例上下文(=> 左侧的内容)。在您的示例中,没有什么可以阻止 r 被实例化为 Int - 但也没有任何强制它;因为有人可能会稍后出现并定义一个实例,例如instance Foo Int (Bool -> ()),尚不清楚现有实例是正确的选择。尽管考虑到当前正在编译的模块,它是唯一匹配的,但开放世界假设意味着以后可以添加更多的编译单元。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-08
相关资源
最近更新 更多