这篇文章是对previous post ...
的跟进我正在尝试以通用方式处理更新结构的子问题,最终目标是能够编写类似的内容:
g = graft idx "foo" obj
where
idx = Proxy :: Proxy '[1,0]
obj = Ap Obj3 (Ap F1 ((12 :: Int):-: ("bar" :: Text)) :-: Ap F2 ("baz" :: Text))
以下是对预期"语义的一些澄清" graft
:
obj
是一个以通用方式表示某些数据结构的多路树。它应该由2个元素构成:嵌套对表示(水平)节点序列,Ap f a
表示某些函数f
被暂停应用于某个参数a
,其中a
}可以是所提到的一系列参数,obj
的类型具有模仿值的树结构的类型,但当然使用类型而不是值作为节点,idx
代表多路树obj
中的路径,作为到达树中某个点的索引序列graft
然后将obj
处的path
元素替换为其他值(例如"foo"
)。我们的想法是graft
递归地从树的根处起作用,跟随path
的每个段,直到它找到节点并用a
替换值,所有这些都是以类型安全的方式:替换值a
应与嫁接树中path
处的节点具有相同的类型。在给定示例的情况下,当评估g
时,它应该产生以下结构:
obj = Ap Obj3 (Ap F1 (12 :-: "bar") :-: Ap F2 "foo")
我试图定义Graft
类型类来处理给定路径的数据结构:
class Graft a path b where
graft :: path -> a -> b -> b
然后使用Nat
s:
type a :-: b = (a, b)
infixr 5 :-:
pattern (:-:) :: a -> b -> (a ,b)
pattern a :-: b = (a ,b)
instance Graft a (Proxy '[0]) (a :-: b) where
graft _ a (_ :-: b) = a :-: b
instance Graft a (Proxy '[]) a where
graft _ a _ = a
当我尝试递归地应用graft
时出现问题。以下实例不编译
instance (Graft a (Proxy k) b) => Graft a (Proxy (0 ': k)) (b :-: c) where
graft _ a (b :-: c) = graft p a b :-: c
where
p = Proxy :: Proxy k
产生消息:
error:
• Could not deduce (Graft a (Proxy k4) b)
arising from a use of ‘graft’
from the context: Graft a (Proxy k) b
bound by the instance declaration
at /Users/arnaud/projects/gorillaspace/gorilla-space/hevents/.stack-work/intero/intero398uMH.hs:65:10-68
The type variable ‘k4’ is ambiguous
Relevant bindings include
b :: b
(bound at /Users/arnaud/projects/gorillaspace/gorilla-space/hevents/.stack-work/intero/intero398uMH.hs:66:14)
a :: a
(bound at /Users/arnaud/projects/gorillaspace/gorilla-space/hevents/.stack-work/intero/intero398uMH.hs:66:11)
graft :: Proxy (0 : k) -> a -> b :-: c -> b :-: c
(bound at /Users/arnaud/projects/gorillaspace/gorilla-space/hevents/.stack-work/intero/intero398uMH.hs:66:3)
• In the first argument of ‘(:-:)’, namely ‘graft p a b’
In the expression: graft p a b :-: c
In an equation for ‘graft’:
graft _ a (b :-: c)
= graft p a b :-: c
where
p = Proxy :: Proxy k
以下完成遍历的实例也不会编译,产生相同类型的错误:
instance (Graft a (Proxy (n-1 : k)) c) => Graft a (Proxy (n ': k)) (b :-: c) where
graft _ a (b :-: c) = b :-: graft p a c
where
p = Proxy :: Proxy (n-1 : k)
instance (Graft a (Proxy k) b) => Graft a (Proxy (0 ': k)) (Ap f b c) where
graft _ a (Ap f b) = Ap f (graft p a b)
where
p = Proxy :: Proxy k
所以似乎结构化的类型级变量k
不是"可见"在对graft
的递归调用中,我不知道如何解决这个问题。