haskell中重叠的实例

时间:2013-05-11 05:22:14

标签: haskell types metaprogramming

我正在阅读HList库的代码。有一个HBetween类,它是一个类型级函数,它带有HNat n并返回一个HNat s列表,形成一个范围[HZero,n)。我想实现另一个类HRange,它有一个重载函数hRange :: l -> u -> r,它接受​​一个低限l和一个上限u并返回一个范围[l,u )。我的代码如下(为了使代码更清晰,hRange的结果是相反的顺序,比如说(u,l))

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, 
    FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
module Data.HList.HNats where
import Data.HList.CommonMain
class (HNat l, HNat u) => HRange l u r | l u -> r where
  hRange :: l -> u -> r
instance HNat l => HRange l (HSucc l) (HCons l HNil) where
  hRange _ _ = undefined
instance HRange l u r => HRange l (HSucc u) (HCons u r) where
  hRange _ _ = undefined

我在ghci中尝试了这个代码,发生了意想不到的事情:

*Data.HList.HNats Data.HList> :load Data/HList/HNats
[1 of 1] Compiling Data.HList.HNats ( Data/HList/HNats.hs, interpreted )
Ok, modules loaded: Data.HList.HNats.
*Data.HList.HNats Data.HList> hRange hZero (hSucc hZero )

<interactive>:24:1:
    Overlapping instances for HRange
                                HZero (HSucc HZero) (HCons HZero HNil)
      arising from a use of `hRange'
    Matching instances:
      instance HNat l => HRange l (HSucc l) (HCons l HNil)
        -- Defined at Data/HList/HNats.hs:14:10
      instance HRange l u r => HRange l (HSucc u) (HCons u r)
        -- Defined at Data/HList/HNats.hs:20:10
    In the expression: hRange hZero (hSucc hZero)
    In an equation for `it': it = hRange hZero (hSucc hZero)
*Data.HList.HNats Data.HList> 

我不知道为什么hRange hZero (hSucc hZero )可以匹配实例instance HRange l u r => HRange l (HSucc u) (HCons u r)。任何解释都表示赞赏!

1 个答案:

答案 0 :(得分:3)

请注意,GHC将hRange hZero (hSucc hZero)的类型设为HRange HZero (HSucc HZero) (HCons Zero HNil)。因为GHC实例匹配器在选择匹配之前不考虑约束,所以它只检查HRange l (HSucc u) (HCons u r)l可以匹配任何内容,因此匹配HZero; HSucc uHSucc HZeroHCons u r明显匹配HCons HZero HNil

一般来说,就GHC而言,你的第二个实例是第一个实例的严格超集,因为右边的唯一差异(因此忽略约束HNat lHRange l u r),在选择实例时,第一个是r限制为HNil的第二个实例。解决这个问题的正常方法是投入一个幻像类型或类来区分右侧,虽然我不知道如何在这里做到这一点。