如何一般地替换Haskell数据结构的某些部分?

时间:2017-02-15 08:28:31

标签: haskell generics types type-level-computation

这篇文章是对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

  1. obj是一个以通用方式表示某些数据结构的多路树。它应该由2个元素构成:嵌套对表示(水平)节点序列,Ap f a表示某些函数f被暂停应用于某个参数a,其中a }可以是所提到的一系列参数,
  2. 每个"实例" obj的类型具有模仿值的树结构的类型,但当然使用类型而不是值作为节点,
  3. idx代表多路树obj中的路径,作为到达树中某个点的索引序列
  4. graft然后将obj处的path元素替换为其他值(例如"foo")。我们的想法是graft递归地从树的根处起作用,跟随path的每个段,直到它找到节点并用a替换值,所有这些都是以类型安全的方式:替换值a应与嫁接树中path处的节点具有相同的类型。
  5. 在给定示例的情况下,当评估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的递归调用中,我不知道如何解决这个问题。

0 个答案:

没有答案