【问题标题】:Is this use of UndecidableInstances okay? Alternatives?使用 UndecidableInstances 可以吗?备择方案?
【发布时间】:2012-08-02 10:03:08
【问题描述】:

我想在库中做一些魔术,允许以多态方式解构产品类型。这是一个或多或少的工作模型,说明了我想做的事情:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-} 
newtype Wrapped a = Wrapped { unwrap :: a } 

-- our example structure
ex :: (Int, (Int, Int))
ex = (1,(2,3))

class WrapDecomp x y | y -> x where
    decomp :: x -> y

instance (WrapDecomp x x', WrapDecomp y y')=> WrapDecomp (x,y) (x',y') where
    decomp (x,y) = (decomp x, decomp y)

instance WrapDecomp x (Wrapped x) where
    decomp = Wrapped


example = let w = decomp ex
              (w0, w1) = decomp ex
              (w0', (w1', w2')) = decomp ex :: (Wrapped Int, (Wrapped Int, Wrapped Int))
           in print $ ( unwrap w, unwrap w0, unwrap $ snd w1, unwrap $ fst w1 )
         -- Also works:
         -- in print $ ( unwrap w, unwrap w0, unwrap w1 )

我的实际应用程序是一个库,并且将具有两个属性,使上述我注意到中的疣可以接受:

  1. Wrapped 类型构造函数未导出

  2. 用户将始终在绑定中的所有 Wrapped 数据上调用 unwrap(因为我的应用程序的细节很无聊),因此在实践中不应有歧义

大家的共识似乎是 UndecidableInstances 还不错,但我想在继续之前确定以上内容是否符合犹太教规。


更新解决方案

我对此感到困惑,但我能够通过TypeFamilies 解决我的问题,如下所示:

{-# LANGUAGE TypeFamilies #-}
class Out a where
    type In a :: *
    decomp :: In a -> a

instance Out (Wrapped a) where
    type In (Wrapped a) = a
    decomp = Wrapped

instance (Out a, Out b)=> Out (a,b) where
    type In (a,b) = (In a,In b)
    decomp (x,y) = (decomp x, decomp y)

【问题讨论】:

  • 我不知道您是否注意到与 newtype package 中的类型类“Newtype”的相似之处您的包装物品对实例与库似乎预期的任何东西都不同.
  • 以前没听说过这个包,谢谢!不过,我不确定这对我有帮助。
  • @jberryman 我错了。您可以使用使类型检查器循环的那些实例编写表达式。然而,这仍然是正确的:上下文堆栈阻止类型检查器实际循环,并且编译的代码(即没有导致循环的表达式)是安全的。
  • @DanielFischer IYI 我想出了一个使用TypeFamilies 的解决方案并在上面进行了编辑。感谢您帮助我了解UndecidableInstances

标签: haskell types ghc type-families


【解决方案1】:

单独使用UndecidableInstances 通常是犹太洁食,UndecidableInstances 所做的是允许类型检查器在无法提前证明它将完成时尝试解析实例。如果是这样,则代码的安全性不亚于可以提前证明终止。

但是,对于您的实例,您可以创建一种情况,其中类型检查器将使用导致约束 WrapDecomp x (x,y) 的表达式循环,例如

foo x = [fst $ decomp x, x]

fst 的使用要求 decomp x 对于某些类型 ab 具有类型 (a,b),因此是 instance WrapDecomp t (a,b),其中 tx 的类型。在同一个列表中需要x 也有磁带a,所以

instance WrapDecomp a (a,b)

第二个参数有一对的唯一实例是

instance (Wrapdecomp x x', WrapDecomp y y') => WrapDecomp (x,y) (x',y')

因此 a = (x,y) 对于某些类型 xyfoo 的约束变为

WrapDecomp (x,y) ((x,y),b)

pairs 实例表示如果有实例就有这样的实例

WrapDecomp y b

WrapDecomp x (x,y)

这是我们开始使用的实例的确切形式。

【讨论】:

  • 谢谢,丹尼尔!这澄清了事情。看来你是非官方的 UndecidableInstances 手持设备 ;)
  • 不是UndecidableInstances,这种情况下只需要解除覆盖条件吗?
猜你喜欢
  • 2012-12-07
  • 2011-06-10
  • 2011-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-06
相关资源
最近更新 更多