请原谅我如果我使用了错误的术语,因为我在Haskell类型操作方面还是个新手... 我试图使用具有功能依赖的重叠实例来进行一些与HLists相关的类型级编程。
我的目标是尝试编写一个类型类 HNoNils l l',其中 HNoNils l l' 表示对于 l 作为列表类型(例如:Int:String:EmptyNil:Int:HNil),l' 是相应的不包含特定空类型 EmptyNil 的列表类型(示例结果:Int:String:Int:HNil)。
当我按原样运行此代码时,所有我的
根据我所了解的,使用
在这里:
我尝试添加约束条件来消除重叠,即通过向第二个实例添加单独的相反等式约束条件:
我不理解第二个匹配。毕竟,在这种情况下,我们将e等于EmptyNil,所以
当重新添加OverlappingInstances时,我得到了更奇怪的错误,我不理解:
第二个语句 "
因此,在试图弄清楚这一点时,我想知道:
- 是否可以获得有关Haskell如何处理实例的更详细信息?其中一些组合似乎是不可能的。即使只有一个解释该机制的文件链接也会很有帮助。 -
我感觉解决方法是自上而下的,而不是自下而上的(在这种情况下,系统永远不会尝试找到这样的实例)。
编辑2:通过向第二个条件添加一个小约束,我得到了预期的行为(请参见McCann对他的答案的评论)。
我的目标是尝试编写一个类型类 HNoNils l l',其中 HNoNils l l' 表示对于 l 作为列表类型(例如:Int:String:EmptyNil:Int:HNil),l' 是相应的不包含特定空类型 EmptyNil 的列表类型(示例结果:Int:String:Int:HNil)。
{-# LANGUAGE ExistentialQuantification,
FunctionalDependencies,
FlexibleInstances,
UndecidableInstances,
OverlappingInstances,
TypeFamilies #-}
import Data.HList
import Data.TypeLevel.Bool
--Type Equality operators
--usedto check if a type is equal to another
class TtEq a b eq | a b -> eq
instance TtEq a a True
instance eq~False => TtEq a b eq
data EmptyNil = EmptyNil deriving (Show) --class representing empty channel
--class intended to generate a list type with no type of EmptyNil
-- Example: HCons Int $ HCons EmptyNil HNil should give HCons Int HNil
class (HList list, HList out) => HNoNils list out | list -> out
where hNoNils :: list -> out
-- l gives l' means (HCons EmptyNil l) gives l'
instance (HNoNils l l',TtEq e EmptyNil True ) => HNoNils (HCons e l) l'
where hNoNils (HCons e l) = hNoNils l
-- l gives l' means (HCons e l) gives (HCons e l') for all e
instance (HNoNils l l') => HNoNils (HCons e l) (HCons e l')
where hNoNils (HCons e l) = hCons e $ hNoNils l
--base case
instance HNoNils HNil HNil
where hNoNils _ = hNil
testList = HCons EmptyNil $ HCons EmptyNil HNil
testList1 = HCons "Hello" $ HCons EmptyNil HNil
testList2 = HCons EmptyNil $ HCons "World" HNil
testList3 = HCons "Hello" $ HCons "World" HNil
main:: IO ()
main = do
print $ hNoNils testList -- should get HNil
print $ hNoNils testList1 -- should get HCons "Hello" HNil
print $ hNoNils testList2 -- should get HCons "World" HNil
print $ hNoNils testList3 -- should get HCons "Hello" (HCons "World" HNil)
当我按原样运行此代码时,所有我的
hNoNils
调用似乎都通过最不具体的第二个实例声明解析,这意味着(至少看起来是这样),对于所有的 l
,我都有 HNoNils l l
。根据我所了解的,使用
OverlappingInstances
扩展,系统应始终解析为最具体的实例。在这里:
第一个实例具有约束条件
(HNoNils l l',TtEq e EmptyNil True )
第二个实例具有约束条件
HNoNils l l'
我尝试添加约束条件来消除重叠,即通过向第二个实例添加单独的相反等式约束条件:
-- l gives l' means (HCons EmptyNil l) gives l'
instance (HNoNils l l',TtEq e EmptyNil True ) => HNoNils (HCons e l) l'
where hNoNils (HCons e l) = hNoNils l
-- l gives l' means (HCons e l) gives (HCons e l') for all e
-- added constraint of TtEq e EmptyNil False
instance (HNoNils l l',TtEq e EmptyNil False) => HNoNils (HCons e l) (HCons e l')
where hNoNils (HCons e l) = hCons e $ hNoNils l
我尝试在这里删除重叠实例扩展,但是出现了重叠错误。
Overlapping instances for HNoNils
(HCons EmptyNil (HCons [Char] HNil)) (HCons EmptyNil l')
Matching instances:
instance (HNoNils l l', TtEq e EmptyNil True) =>
HNoNils (HCons e l) l'
-- Defined at /home/raphael/Dropbox/IST/AFRP/arrow.hs:32:10
instance (HNoNils l l', TtEq e EmptyNil False) =>
HNoNils (HCons e l) (HCons e l')
-- Defined at /home/raphael/Dropbox/IST/AFRP/arrow.hs:36:10
我不理解第二个匹配。毕竟,在这种情况下,我们将e等于EmptyNil,所以
TtEq e EmptyNil True
...对吧?而且,就此而言,类型系统是如何进入询问这个问题的情况的,毕竟有了这些约束条件,你应该永远不会出现HNoNils(Hcons EmptyNil l)(HCons EmptyNil l')
这样的情况,至少我认为不会。当重新添加OverlappingInstances时,我得到了更奇怪的错误,我不理解:
Couldn't match type `True' with `False'
When using functional dependencies to combine
TtEq a a True,
arising from the dependency `a b -> eq'
in the instance declaration at /home/raphael/Dropbox/IST/AFRP/arrow.hs:23:14
TtEq EmptyNil EmptyNil False,
arising from a use of `hNoNils'
at /home/raphael/Dropbox/IST/AFRP/arrow.hs:53:13-19
In the second argument of `($)', namely `hNoNils testList2'
In a stmt of a 'do' block: print $ hNoNils testList2
第二个语句 "
TtEq EmptyNil EmptyNil False
" 似乎表明实例是通过函数调用生成的...? 我有点困惑它从哪里来。因此,在试图弄清楚这一点时,我想知道:
- 是否可以获得有关Haskell如何处理实例的更详细信息?其中一些组合似乎是不可能的。即使只有一个解释该机制的文件链接也会很有帮助。 -
OverlappingInstances
的工作方式是否有更具体的定义?我感觉自己缺少了什么(比如 "特定性" 参数是否仅与类型变量相关,而不是约束数量...)
编辑:所以我尝试了C.A. McCann的建议之一(删除一些约束),如下所示:instance (HNoNils l l') => HNoNils (HCons EmptyNil l) l'
instance (HNoNils l l') => HNoNils (HCons e l) (HCons e l')
instance HNoNils HNil HNil
这样做会导致一些令人讨厌的重叠实例错误:
Overlapping instances for HNoNils
(HCons EmptyNil (HCons [Char] HNil)) (HCons EmptyNil l')
arising from a use of `hNoNils'
Matching instances:
instance [overlap ok] HNoNils l l' => HNoNils (HCons EmptyNil l) l'
-- Defined at /Users/raphael/Dropbox/IST/AFRP/arrow.hs:33:10
instance [overlap ok] HNoNils l l' =>
HNoNils (HCons e l) (HCons e l')
-- Defined at /Users/raphael/Dropbox/IST/AFRP/arrow.hs:37:10
我感觉解决方法是自上而下的,而不是自下而上的(在这种情况下,系统永远不会尝试找到这样的实例)。
编辑2:通过向第二个条件添加一个小约束,我得到了预期的行为(请参见McCann对他的答案的评论)。
-- l gives l' means (HCons EmptyNil l) gives l'
instance (HNoNils l l') => HNoNils (HCons EmptyNil l) l'
where hNoNils (HCons EmptyNil l) = hNoNils l
-- l gives l' means (HCons e l) gives (HCons e l') for all e
instance (HNoNils l l',r~ HCons e l' ) => HNoNils (HCons e l) r
where hNoNils (HCons e l) = hCons e $ hNoNils l
在第二个实例中新增的约束条件是 r~HCons e l'
。