如何为Haskell二叉树GADT定义Arrow示例?

isr3a4wc  于 2023-11-18  发布在  其他
关注(0)|答案(1)|浏览(123)

我尝试在Haskell中使用箭头操作一个通用的二叉树,我在示例化Arrow类时遇到了问题。我认为我的问题是由于类中不兼容的类型签名,但是如果我不能示例化,我怎么能在函数中混合使用在树上工作的箭头操作符和正常的箭头操作呢?
下面是我的简单定义,主要是从Haskell wiki中提取的(first不会编译,这并不奇怪,因为它的签名是a b c -> a (b, d) (c, d),而Tree不是元组)。first基本上说明了我想做的事情:

data Tree a = Empty | Branch a (Tree a) (Tree a)
              deriving (Show, Eq)

newtype ArrowTree a b = ArrowTree {
  evaluate :: a -> b
}

instance Category ArrowTree where
  (ArrowTree f) . (ArrowTree g) = ArrowTree (f . g)
  id = arr id

instance Arrow ArrowTree where 
  arr f = ArrowTree f
  first = ArrowTree mapF
    where mapF g (Branch a l r) = Branch a (g l) r
          mapF g Empty = Empty

字符串
有什么想法吗?我有一个使用loop***的自定义定义来独立地在树的两边递归操作的愿景。谢谢!

yk9xbfzb

yk9xbfzb1#

你说你想对树而不是元组使用箭头操作,但它不是拥有箭头示例的元组类型!
提供Arrow类的示例不会得到first::(B -> c)-> Tree B -> Tree c,它会得到类似first::Tree B c -> Tree(B,d)(c,d)的结果(如果Tree有两个类型参数)。如果我们首先考虑基本的:(B -> c)->(B,d)->(c,d),Arrow类没有抽象出元组并允许你泛化它,它抽象出函数箭头(因此命名为Arrow)。元组仍然是硬编码的。泛化如下:

first :: (b  -> c) -> ((b, d)  -> (c, d))
first :: (b `a` c) -> ((b, d) `a` (c, d))

字符串
只有两个内部函数箭头被替换为箭头类型a,并且a是您在特定示例中可以替换为您自己的类型的所有内容。无论您使用 * 什么 * 示例,您都不能将元组替换为Trees。
一个Arrow需要有两个类型参数,您应该能够从概念上将其看作是在某些情况下“从一种类型到另一种类型”的表示。你的树类型看起来一点也不像Arrow;它有一个类型参数,它只包含该类型的值,它不包含任何从该类型到其他类型的方法。
你的ArrowTree * 确实 * 有两个类型参数ab,它包含的是一个a -> b函数,所以很明显它支持“从ab“的概念。但是因为它和普通函数完全一样,它将是一个Arrow,就像一个普通的函数一样,这并不能真正帮助你在树上使用first***这样的操作,而不是元组。
如果你想把普通函数提升到树上,就像箭头操作可以把普通函数提升到元组上一样,那么听起来你根本不需要一个自定义的Arrow示例。你不需要自定义的“函数”,你想要的是应用到树上的普通函数。所以如果Arrow能帮到你的话,这将是通过使用Arrow的普通函数示例来 * 实现 * 新函数(不作为任何类型类的一部分),将函数提升到树上。

相关问题