此代码无法编译:
data Foo = A String | B (List Foo)
Eq Foo where
(==) (A x) (A y) = x == y
(==) (B xs) (B ys) = xs == ys
(==) _ _ = False
它会产生以下错误:
类型检查./eq.idr eq.idr:11:3-27:| 11 | (==)(A x)(A y)= x == y | ~~~~~~~~~~~~~~~~~~~~~~~~~ Prelude.Interfaces.Main.Foo Prelude.Interfaces.Eq的实现,方法==可能不是 总计由于递归路径Prelude.Interfaces.Main.Foo实现 of Prelude.Interfaces.Eq,method == - > Prelude.Interfaces.Main.Foo Prelude.Interfaces.Eq,method ==
的实现
这里的问题是,我们在实现中依赖Eq Foo
,因此递归路径?这似乎没有解释它,因为这编译:
data Bar = C String | D Bar
Eq Bar where
(==) (C x) (C y) = x == y
(==) (D x) (D y) = x == y
(==) _ _ = False
所以 - 我可以对我在定义实现的任何内容进行==
的递归调用,但我不能列出它的列表?我是否错过了使这项工作成功的技巧,或者我是否正试图做一些从根本上被破坏的事情?
答案 0 :(得分:0)
决定相等性的函数需要在相互递归方面实现,就像Foo
本身是由相互递归定义一样。
Eq Foo where
(==) = eq
where mutual -- massive indentation necessary
eq : Foo -> Foo -> Bool
eq (A l) (A r) = l == r
eq (B l) (B r) = eq1 l r
eq _ _ = False
eq1 : List Foo -> List Foo -> Bool
eq1 (l :: ls) (r :: rs) = eq l r && eq1 ls rs
eq1 [] [] = True
eq1 _ _ = False
您不能重复使用List
自己的(==)
,但可以将模式分解出来。
zipWithFoldrElem : (ls : List a) -> (rs : List a) -> ((l : a) -> (r : a) -> Elem (l, r) (zip ls rs) -> b) -> (b -> Lazy b -> b) -> b -> b -> b -> b
zipWithFoldrElem [] [] _ _ e _ _ = e
zipWithFoldrElem [] (_ :: _) _ _ _ el _ = el
zipWithFoldrElem (_ :: _) [] _ _ _ _ er = er
zipWithFoldrElem (l :: ls) (r :: rs) f g e el er = f l r Here `g` zipWithFoldLazyElem ls rs (\l, r, e => f l r (There e)) g e el er
Eq Foo where
(A l) == (A r) = l == r
(B l) == (B r) = zipWithFoldrElem l r (f l r) (&&) True False False
where f : (ls : List Foo) -> (rs : List Foo) -> (l : Foo) -> (r : Foo) -> Elem (l, r) (zip ls rs) -> Bool
f (l :: _) (r :: _) l r Here = l == r
f (_ :: ls) (_ :: rs) l r (There e) = f ls rs l r e
f [] [] _ _ _ impossible
_ == _ = False
而且,对于show,这是一个词典Ord
:
Ord Foo where
compare (A l) (A r) = l `compare` r
compare (B l) (B r) = zipWithFoldrElem l r (f l r) thenCompare EQ LT GT
where f : (ls : List Foo) -> (rs : List Foo) -> (l : Foo) -> (r : Foo) -> Elem (l, r) (zip ls rs) -> Ordering
f (l :: _) (r :: _) l r Here = l `compare` r
f (_ :: ls) (_ :: rs) l r (There e) = f ls rs l r e
f [] [] _ _ _ impossible
compare (A _) (B _) = LT
compare (B _) (A _) = GT
答案 1 :(得分:0)
现在我已经有了一个更好的方式,我已经WellFounded
了一下。
此数据类型为Foo
,Elem
为List
。它会告诉您在Foo
中找到子Foo
的位置。
-- s is smaller than b if either ...
data Smaller : (s : Foo) -> (b : Foo) -> Type where
-- it is one of the elements of ss when b = B ss
Surface : Elem s ss -> Smaller s (B ss)
-- it is smaller than one of the elements of ms when b = B ms
-- "m" is for "medium"
Deeper : Smaller s m -> Elem m ms -> Smaller s (B ms)
Smaller
是WellFounded
:
WellFounded Smaller where
wellFounded x = Access (acc x)
where mutual
acc : (b : Foo) -> (s : Foo) -> Smaller s b -> Accessible Smaller s
acc (B ss) s (Surface e) = accSurface ss s e
acc (B ms) s (Deeper {m} sr e) = accDeeper ms m e s sr
accSurface : (ss : List Foo) -> (s : Foo) -> Elem s ss -> Accessible Smaller s
accSurface (s :: _) s Here = Access (acc s)
accSurface (_ :: ss) s (There e) = accSurface ss s e
accDeeper : (ms : List Foo) -> (m : Foo) -> Elem m ms -> (s : Foo) -> Smaller s m -> Accessible Smaller s
accDeeper (m :: _) m Here s sr = acc m s sr
accDeeper (_ :: ms) m (There e) s sr = accDeeper ms m e s sr
这使用了相互递归,就像我的旧答案一样,但它更清晰地抽象出来。 WellFounded
实例的一般框架是:
WellFounded (rel : a -> a -> Type) where -- rel s b means s is smaller than b
wellFounded x = Access (acc x)
where acc : (b : a) -> (s : a) -> rel s b -> Accessible rel s
-- Accessible is really cryptic:
-- Access : (rec : (y : a) -> rel y x -> Accessible rel y) -> Accessible rel x
-- but the idea of acc is simple:
-- we convince the totality checker s is really smaller than b
-- acc needs to be recursive, and when it convinces the totality
-- checker, it can end with Access (acc s)
WellFounded
买了我们
wfRec : WellFounded rel =>
(step : (x : a) ->
(rec : (y : a) -> rel y x -> b) ->
b
) ->
a -> b
step
是由开放递归定义的函数。 step
得到一个参数rec
,step
调用rec
而不是递归到自身,并证明其正在递归的参数是正确的大小,wfRec
将回拨路由回step
(基本上是fix : (step : (rec : (a -> b)) -> (x : a) -> b) -> a -> b; fix f x = f (fix f) x
但总共。{/ p>
我们现在可以干净利落地排除列表上(==)
的逻辑:
eqBy : (ls : List a) -> (rs : List a) -> ((l : a) -> (r : a) -> (el : Elem l ls) -> (er : Elem r rs) -> Bool) -> Bool
eqBy (l :: ls) (r :: rs) eq = eq l r Here Here && eqBy ls rs (\l, r, el, er => eq l r (There el) (There er))
eqBy [] [] _ = True
eqBy _ _ _ = False
Eq
实例并不比天真的实例差多少:
Eq Foo where
(==) = wfRec step
where step : (x : Foo) -> ((y : Foo) -> Smaller y x -> Foo -> Bool) -> Foo -> Bool
step (A l) _ (A r) = l == r
step (B l) rec (B r) = eqBy l r (\l, r, el, er => rec l (Surface el) r)
step _ _ _ = False
eqBy
和WellFounded
实例现在比我之前创建的zipWithFoldrElem
憎恶更可重复使用。