是否有基于终端及其祖先映射递归数据类型的名称?

2024-02-11

假设我有一个如下所示的类型:

data Term a = Terminal a
| Application (Term a) (Term a)
| Abstraction String (Term a)

现在,我想绘制地图Term a to Term b。理想情况下,我可以使用函数来做到这一点(a -> b)并执行fmap。但是,这对我不起作用。地图来自Terminal a to Terminal b不仅取决于值a,也是祖先的价值观Terminal a(例如深度Terminal a)。所以它更像是[Term a] -> b这很混乱,所以我试图将其分解为更干净的东西。

所以实际上,我需要的是 2 个函数和一个初始值:(c -> Term a -> c)可以召唤每一个祖先来积累我们想要的东西。 (我想这相当于([Term a] -> c)但我不确定这是否会让情况变得混乱或有帮助。)(c -> a -> b)可以映射Terminal a to Terminal b。 (我们还需要一个类型的初始值c)

所以我定义了一个具有以下类型签名的函数:

notQuiteANatTrans :: (c -> Term a -> c) -> (c -> a -> b) -> c -> Term a -> Term b

这不是自然的转变。 (我不认为)或者如果是的话,它正在映射类似的东西[Term a] -> [Term b]其中每一个都是从树的根到Terminal。这个有名字吗?是否有不同的方法来分解我的箭头以获得更干净的东西?


我不确定我完全理解这个问题,所以如果以下内容偏离了不相关的切线,我深表歉意......

地图来自Terminal a to Terminal b不仅取决于值a,也是祖先的价值观Terminal a(例如深度Terminal a).

这听起来让人想起必须检查一棵树才能找到它的深度等。对于一棵树,你可以用它的变态作用- 参见例如FoldTree 的示例 https://hackage.haskell.org/package/containers/docs/Data-Tree.html#v:foldTree.

一般来说,如果您知道数据类型的变形,您可以从中派生出大多数其他(也许全部?)有用的函数。那么变形现象是为了什么Term a?

F-代数

你可以从F-代数 https://bartoszmilewski.com/2017/02/28/f-algebras/。我将遵循我使用过的流程我自己的关于变态现象的文章系列 https://blog.ploeh.dk/2019/04/29/catamorphisms.

像这样定义底层的endofunctor:

data TermF a c =
    TerminalF a
  | ApplicationF c c
  | AbstractionF String c
  deriving (Eq, Show)

instance Functor (TermF a) where
  fmap _ (TerminalF a) = TerminalF a
  fmap f (ApplicationF x y) = ApplicationF (f x) (f y)
  fmap f (AbstractionF s x) = AbstractionF s (f x)

这使您能够通过使用来找出变形现象型孔 https://wiki.haskell.org/GHC/Typed_holes:

termF = cata alg
  where alg      (TerminalF x) = _
        alg (ApplicationF x y) = _
        alg (AbstractionF s c) = _

如果您尝试编译此草图,编译器将抱怨类型漏洞并告诉您需要什么。我使用这个过程来实现这个函数:

termF :: (a -> c) -> (c -> c -> c) -> (String -> c -> c) -> Fix (TermF a) -> c
termF t appl abst = cata alg
  where alg      (TerminalF x) = t x
        alg (ApplicationF x y) = appl x y
        alg (AbstractionF s x) = abst s x

变形需要底层类型的映射器a -> c,以及每个递归节点的“累加器”。

同构

Fix (TermF a)同构于Term a,正如这两个转换函数所证明的:

toTerm :: Fix (TermF a) -> Term a
toTerm = termF Terminal Application Abstraction

fromTerm :: Term a -> Fix (TermF a)
fromTerm = ana coalg
  where coalg      (Terminal x) = TerminalF x
        coalg (Application x y) = ApplicationF x y
        coalg (Abstraction s x) = AbstractionF s x

这意味着您可以轻松定义变形Term a利用变形论Fix (TermF a)。我们就这样称呼它吧foldTerm,因为这可能更惯用一点:

foldTerm :: (a -> c) -> (c -> c -> c) -> (String -> c -> c) -> Term a -> c
foldTerm t appl abst = termF t appl abst . fromTerm

现在您知道了类型foldTerm,你可以扔掉所有的TermF机械并直接实施。

直接实施

同样,您可以使用类型化孔来实现更简单、更直接的实现:

foldTerm :: (a -> c) -> (c -> c -> c) -> (String -> c -> c) -> Term a -> c
foldTerm t appl abst      (Terminal x) = _
foldTerm t appl abst (Application x y) = _
foldTerm t appl abst (Abstraction s x) = _

编译器会告诉你需要什么,而且很明显,实现必须是这样的:

foldTerm :: (a -> c) -> (c -> c -> c) -> (String -> c -> c) -> Term a -> c
foldTerm t appl abst      (Terminal x) = t x
foldTerm t appl abst (Application x y) = appl (recurse x) (recurse y)
  where recurse = foldTerm t appl abst
foldTerm t appl abst (Abstraction s x) = abst s (foldTerm t appl abst x)

请记住,输出foldTerm可以是任何类型c, 包括Term b: c ~ Term b。这能让你做你所要求的事情吗?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否有基于终端及其祖先映射递归数据类型的名称? 的相关文章

  • 如何对对象数组调用reduce来求和它们的属性?

    说我想求和a x对于中的每个元素arr arr x 1 x 2 x 4 arr reduce function a b return a x b x gt NaN 我有理由相信a x is undefined在某一点 以下工作正常 arr
  • Haskell 中的多态函数作为参数

    我有一个带有两个构造函数的 ADT 一个包裹着一个Double和一个包裹着Integer 我想创建一个函数 它采用一元函数Numtypeclass 并返回一个函数 该函数将该一元函数应用于我的 ADT 的内容 我试过这个 data X Y
  • 我应该用不可变或可变的数据结构来表示数据库数据吗?

    我目前正在使用 Scala 进行编程 但我想这适用于任何函数式编程语言 或者更确切地说 任何建议不变性并可以与数据库交互的编程语言 当我从数据库中获取数据时 我将其映射到模型数据结构 在函数式编程中 数据结构往往是不可变的 但是数据库中的数
  • 是否有适用于 Haskell 或 Scala 等函数式语言的 LL 解析器生成器?

    我注意到明显缺乏用函数式语言创建解析器的 LL 解析器 我一直在寻找但没有成功的理想发现是为 ANTLR 风格的 LL 语法生成 Haskell 解析器 语法的模小数重新格式化 并且令我惊讶的是 每个最后一个解析器生成器都具有函数我发现的语
  • 为什么 Haskell (Hugs) 中的 Show 实例会导致堆栈溢出错误?

    下面是 Haskell 中的多态数据类型 由 Hugs 解释 我正在尝试创建一个 Show for Equality 的实例 实例声明表示 如果类型 a 在 Show 中 则相等 a 在 Show 中 它应该以 a b 的形式打印构造函数
  • Repa 数组上的并行 mapM

    在我最近的work https github com bgamari mixture model with Gibbs sampling 我一直在充分利用RVar http hackage haskell org packages arch
  • Javascript 与 Python 关于 Python 'map()' 函数的比较

    Python中有一个函数叫做map这可以让你去 map someFunction x y z 并继续应用该功能的列表 是否有与此功能等效的 JavaScript 我现在刚刚学习Python 虽然我被告知javascript是函数式语言 但我
  • 如何在 GHCJS 程序中定期执行操作?

    应该有人使用setInterval通过Javascript 或者使用一些更惯用的基于线程的解决方案 Using setInterval posed 一些挑战 https stackoverflow com questions 3357661
  • 计算出类型索引的自由 monad 的细节

    我一直在使用免费的 monad 来构建 DSL 作为语言的一部分 有一个input命令 目标是在类型级别反映输入原语期望的类型 以提高安全性 例如 我希望能够编写以下程序 concat Action String String concat
  • ~/.cabal/config 中的“共享”是什么意思?

    我想 共享 会让cabal install更快 对吧 共享的默认值为 False 我们应该使用 True 还是 False 来共享 thanks 这意味着 还构建动态链接 又名共享 版本的库 这些版本与cabal install cabal
  • Javascript 作为一种函数式语言

    我正在寻求掌握函数式编程概念 我多年来一直在 Web 应用程序中使用 Javascript 进行客户端脚本编写 除了使用原型之外 它都是简单的 DOM 操作 输入验证等 最近 我有经常阅读 http eloquentjavascript n
  • enumFromTo 如何工作?

    我无法将号码添加到Char 以下内容将无法编译 a 1 但是 a z 成功创建一个字符串 其中每个字符值都会递增 有没有一个特殊的函数可以增加Char 我知道我能做到chr ord c 1 如何 a z 或底层enumFromTo函数增加结
  • 使用 GHC.Generics 恢复类型定义

    昨天我尝试回答这个问题是关于数据类型的表示 https stackoverflow com questions 22715572 a serializable representation of a data type for client
  • 从 Monoids 的 HList 类型派生 0 的 HList

    我正在学习 Shapeless 目前我正在尝试创建一个执行以下操作的函数 给定一个类型HList它返回HList of Nones 与Option对应于给定的类型HList type 例如 create String Int HNil re
  • Haskell 中存在量化值的列表

    我想知道为什么这段代码不进行类型检查 LANGUAGE ScopedTypeVariables Rank2Types RankNTypes OPTIONS fglasgow exts module Main where foo forall
  • 记录语法和求和类型

    我有关于 Haskell 中的总和类型的问题 我想创建一个由两个或多个其他类型组成的总和类型 并且每个类型可能包含多个字段 一个简单的例子是这样的 data T3 T1 a Int b Float T2 x Char deriving Sh
  • Haskell - 让函数返回空字符

    我正在尝试创建一个函数来删除字符串中的每个第 n 个元素 dropEvery String gt Int gt String dropEvery str n map char indx gt if indx mod n 0 then cha
  • Haskell 中的 Monad 和 Purity

    我的问题是 Haskell 中的 monad 是否真正保持了 Haskell 的纯度 如果是的话 又是如何保持的 我经常读到副作用是如何不纯粹的 但有用的程序 例如 I O 需要副作用 下一句指出 Haskell 对此的解决方案是 mona
  • 为什么阴谋集团重新安装“总是危险的”?

    使用 Cabal 重新安装软件包时 通常会看到以下警告 警告 请注意 重新安装总是很危险的 无论如何继续 此消息背后的一些原因是什么 目前 重新安装软件包意味着破坏性地覆盖已安装的软件包 如果旧包对系统有任何反向依赖性 它们将不再工作 为了
  • Haskell 程序查找列表中元素的位置

    我需要编写一个函数来查找列表中一个特定元素的位置 我是这样写的 findPos list elt list 1 head list elt 0 otherwise 1 findPos tail list elt 但是如果列表中元素重复怎么办

随机推荐