假设我有一种看起来像这样的类型:
data Term a = Terminal a
| Application (Term a) (Term a)
| Abstraction String (Term a)
现在,我想将术语
术语b
映射。理想情况下,我将能够使用函数(a - > b)
进行此操作,并且只需实现 fmap
。但是,这对我不起作用。 终端A
到终端B
的地图不仅取决于 a
的值,还取决于祖先的值终端A
(例如终端A
的深度)。因此,它更像是 [术语A] - > b
是凌乱的,所以我试图将其分解为更清洁的东西。
因此,实际上,我需要的是两个功能和一个初始值:(c - >术语a - > c)
可以在每个祖先上调用,以累积我们想要的任何东西。 (我猜这相当于([[术语a] - > c)
,但我不确定是混淆情况还是有帮助的。)(c - > a - > b)
可以映射终端a
<代码>终端b 。 (我们还需要类型 c
的初始值)
因此,我定义具有以下类型签名的函数:
notQuiteANatTrans :: (c -> Term a -> c) -> (c -> a -> b) -> c -> Term a -> Term b
这不是自然转换。 (我不认为)或者,它正在映射 [术语A] - &GT之类的内容; [术语B]
其中每个是从树的根到终端
的路径。有这个名字吗?是否有一种分解我的箭头以获取更清洁的方法?
Let's say I have a type that looks like this:
data Term a = Terminal a
| Application (Term a) (Term a)
| Abstraction String (Term a)
Now, I want to map Term a
to Term b
. Ideally, I would be able to do this using a function (a -> b)
and just implement fmap
. However, that doesn't work for me. The map from Terminal a
to Terminal b
is dependent not just on the value of a
, but also the values of the ancestors of Terminal a
(e.g. the depth of Terminal a
). So it's more like [Term a] -> b
which is messy, so I'm trying to decompose this into something cleaner.
So really, what I need is something like 2 functions and an initial value: (c -> Term a -> c)
can be called on each of the ancestors in order to accumulate whatever we want. (I guess it's equivalent to ([Term a] -> c)
but I'm not sure whether that confuses the situation or helps.) (c -> a -> b)
can map Terminal a
to Terminal b
. (We also need an initial value of type c
)
So I'm definition a function with the following type signature:
notQuiteANatTrans :: (c -> Term a -> c) -> (c -> a -> b) -> c -> Term a -> Term b
This isn't a natural transformation. (I don't think) Or if it is, it's mapping something like [Term a] -> [Term b]
where each of those is the path from the root of the tree to the Terminal
. Is there a name for this? Is there maybe a different way to decompose my arrows in order to get something cleaner?
发布评论
评论(1)
我不确定我是否完全理解这个问题,所以很抱歉,如果以下情况下有无关紧要的切线...
这听起来让人想起必须检查一棵树才能找到它的深度。对于一棵树,您可以使用其 catamormathism - 请参阅Eg foldtree的示例。
通常,如果您知道数据类型的血统,则可以从中得出大多数其他(也许全部?)有用的功能。那么
术语a
的血统是什么?f-algebra
您可以从。
定义基本的内函数:
这使您可以通过使用
如果您尝试编译此草图,则编译器会抱怨孔的类型,并告诉您您需要什么。我使用此过程来达到此功能:
血统需要映射基础类型
a - &gt; C
以及每个递归节点的“累加器”。同构
fix(termf a)
是同构的,术语a
,如这两个转换功能所见:这意味着您可以轻松地定义
术语a
术语的垂直态/code>使用
fix fix(termf a)
的血统。让我们称其为foldterm
,因为这可能有些惯用:现在您知道
foldterm
的类型,您可以丢弃所有termf
机械并直接实施。再次直接实施
,您可以使用键入的孔来实现更简单,更直接的实现:
编译器会告诉您您的需求,很明显,实现必须是这样的:
请记住,
foldterm的输出
可以是任何类型c
,包括术语b
:c〜项b
。这使您可以做您要问的事情吗?I'm not sure I entirely understand the problem, so apologies if the following goes off on an irrelevant tangent...
This sounds reminiscent of having to examine a tree to find, for example, its depth. For a tree, you can do this with its catamorphism - see e.g. the examples for foldTree.
In general, if you know the catamorphism for a datatype, you can derive most other (perhaps all?) useful functions from it. So what's the catamorphism for
Term a
?F-Algebra
You can derive the catamorphism from F-Algebras. I'll follow the process I've used in my own article series on catamorphisms.
Define the underlying endofunctor like this:
This enables you to figure out the catamorphism by using typed holes:
If you try to compile this sketch, the compiler will complain about the type holes and tell you what you need. I used this process to arrive at this function:
The catamorphism requires a mapper of the underlying type
a -> c
, as well as 'accumulators' for each of the recursive nodes.Isomorphism
Fix (TermF a)
is isomorphic withTerm a
, as witnessed by these two conversion functions:This means that you can easily define the catamorphism for
Term a
using the catamorphism forFix (TermF a)
. Let's call itfoldTerm
, as that's probably a little more idiomatic:Now that you know the type of
foldTerm
, you can throw away all theTermF
machinery and implement it directly.Direct implementation
Again, you can use typed holes for a simpler, more direct implementation:
The compiler will tell you what you need, and it's fairly clear that the implementation must be something like this:
Keep in mind that the output of
foldTerm
can be any typec
, includingTerm b
:c ~ Term b
. Does that enable you do do what you're asking about?