解析 haskell 中的 Karva 表示法

2023-12-02

Karva 表示法在基因表达编程中用于表示数学表达式。

看这里http://www.gene-express-programming.com/Tutorial002.asp

您可以通过读取基因并从左到右、从上到下填充节点来创建表达树。

例如,在“+*+1+2*3456”中使用运算符( +、* )和终结符(1,2,3,4,5,6)将得出 39。

我将如何使用 attoparsec (或 parsec)在 haskell 中执行此操作?

karvaParser :: Parser Int
karvaParser = ????????????

Prelude> parse karvaParser "+*+1+2*3456"
Done 39

(我已经证明这是一个线性时间算法这个答案对于评论中提到的问题。有一个更长的、更手动的解决方案之前的修订版这个答案。)

基因表达编程:Karva 符号。

使用连续传递 monad 可能有一个巧妙的解决方案,Cont,但我还没有想到。这是一个相当干净的纯函数式解决方案。我将借此机会列出一些好的通用递归方案。

Plan:

  1. 使用前一行的总数量将输入拆分为列表,每一层一个列表。这是一种变形,即从种子([])并且可以写成unfoldr :: (b -> Maybe (a, b)) -> b -> [a]或同等地,unfoldr' :: (b -> (a, b)) -> (b -> Bool)-> b -> [a]

    input:   "Q/a*+b-cbabaccbac"
    arities:  12022020000000000
    output:  ["Q","/","a*","+b","-c","ba"]
    
  2. 递归使用splitAt将孩子粘在父母下面。这是一种变形,即将列表折叠为单个(树)值,并且可以使用以下方式编写foldr :: (a -> b -> b) -> b -> [a] -> b

  3. 将变形和变形合二为一。这就是所谓的hylomorphism。 这些术语在开创性论文中被引入到 FP 社区使用香蕉、镜头和铁丝网进行函数式编程.

Code

如果你不熟悉的话,Data.Tree补给品data Tree a = Node {rootLabel :: a, subForest :: Forest a} where type Forest a = [Tree a].

import Data.Tree
import Data.Tree.Pretty -- from the pretty-tree package

arity :: Char -> Int
arity c 
  | c `elem` "+*-/" = 2
  | c `elem` "Q" = 1
  | otherwise = 0

hylomorphism :: b -> (a -> b -> b) -> (c -> (a, c)) -> (c -> Bool) -> c -> b
hylomorphism base combine pullout stop seed = hylo seed where
 hylo s | stop s = base
        | otherwise = combine new (hylo s') 
          where (new,s') = pullout s

为了拉出一个级别,我们使用前一个级别的总数量来查找在哪里分割这个新级别,并传递该级别的总数量以供下一次使用:

pullLevel :: (Int,String) -> (String,(Int,String))
pullLevel (n,cs) = (level,(total, cs')) where
                   (level,        cs') = splitAt n cs
                   total = sum $ map arity level

要将一个级别(作为字符串)与下面的级别(已经是一个森林)组合起来,我们只需提取每个角色所需的树数量即可。

combineLevel :: String -> Forest Char -> Forest Char
combineLevel "" [] = []
combineLevel (c:cs) levelBelow = Node c subforest : combineLevel cs theRest 
      where (subforest,theRest) = splitAt (arity c) levelBelow

现在我们可以使用hylomorphism 来解析Karva。请注意,我们用来自字符串外部的总数量作为种子1,因为根级别只有一个节点。我用过head函数因为1使顶层成为包含一棵树的列表。

karvaToTree :: String -> Tree Char
karvaToTree cs = let
  zero (n,_) = n == 0          
    in head $ hylomorphism [] combineLevel pullLevel zero (1,cs) 

Demo

让我们画一下结果(因为 Tree 充满了语法,很难阅读输出!)。你必须cabal install pretty-tree to get Data.Tree.Pretty.

see :: Tree Char -> IO ()
see = putStrLn.drawVerticalTree.fmap (:"")
ghci> arity '+'
2

ghci> pullLevel (3,"+a*bc/acb")
("+a*",(4,"bc/acb"))

ghci> combineLevel "a*" [Node 'b' [],Node 'c' []]
[Node {rootLabel = 'a', subForest = []},Node {rootLabel = '*', subForest = [Node {rootLabel = 'b', subForest = []},Node {rootLabel = 'c', subForest = []}]}]

ghci> see . Node '.' $ combineLevel "a*" [Node 'b' [],Node 'c' []]
   .   
   |   
 ---   
/   \  
a   *  
    |  
    -- 
   /  \
   b  c

ghci> karvaToTree "Q/a*+b-cbabaccbac"
Node {rootLabel = 'Q', subForest = [Node {rootLabel = '/', subForest = [Node {rootLabel = 'a', subForest = []},Node {rootLabel = '*', subForest = [Node {rootLabel = '+', subForest = [Node {rootLabel = '-', subForest = [Node {rootLabel = 'b', subForest = []},Node {rootLabel = 'a', subForest = []}]},Node {rootLabel = 'c', subForest = []}]},Node {rootLabel = 'b', subForest = []}]}]}]}

Which matches
http://www.gepsoft.com/gxpt4kb/Chapter06/section3/pt02.gif as we see when we see it:

ghci> see $ karvaToTree "Q/a*+b-cbabaccbac"
      Q      
      |      
      /      
      |      
 ------      
/      \     
a      *     
       |     
       ----- 
      /     \
      +     b
      |      
     ----    
    /    \   
    -    c   
    |        
    --       
   /  \      
   b  a  

Eval

一旦你有了一棵树,就很容易将其转换为其他东西。让我们用 Karva 表示法计算一个表达式:

action :: (Read num,Floating num) => Char -> [num] -> num
action c = case c of
   'Q' -> sqrt.head
   '+' -> sum
   '*' -> product
   '-' -> \[a,b] -> a - b
   '/' -> \[a,b] -> a / b
   v -> const (read (v:""))

eval :: (Read num,Floating num)  => Tree Char -> num
eval (Node c subforest) = action c (map eval subforest)
ghci> see $ karvaToTree "Q+-*826/12"
      Q      
      |      
      +      
      |      
  -------    
 /       \   
 -       *   
 |       |   
 --    ---   
/  \  /   \  
8  2  6   /  
          |  
          -- 
         /  \
         1  2

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

解析 haskell 中的 Karva 表示法 的相关文章

  • 在 Haskell 中阅读 GraphML

    我正在尝试将包含单个有向图的 GraphML 文件读入 HaskellData Graph http hackage haskell org package containers 0 2 0 1 docs Data Graph html为了
  • Haskell 中的异构多态性(正确方法)

    让一个模块来抽象Area操作 错误的定义 class Area someShapeType where area someShapeType gt Float module utilities sumAreas Area someShape
  • 让 GHC 生成“带进位加法 (ADC)”指令

    下面的代码将表示 192 位数字的两个未装箱字三元组添加到新的未装箱字三元组中 并且还返回任何溢出 LANGUAGE MagicHash LANGUAGE UnboxedTuples import GHC Prim plusWord2 Wo
  • 使用 cabal new-install 重新安装相同版本的软件包

    我正在开发 Haskell 包 我还没有上传到Hackage 版本号是0 1 0 0 我正在使用新风格的 Cabal 命令 为了在我处理包的同时测试它 使库可用于测试项目 我运行cabal new install lib构建包后 然而 我注
  • 使用通用元组函数一次进行多次折叠

    如何编写一个接受类型函数元组的函数ai gt b gt ai并返回一个函数 该函数接受类型元素的元组ai 类型的一个元素b 并将每个元素组合成一个新的元组ai 那是签名应该是这样的 f a1 gt b gt a1 a2 gt b gt a2
  • 我可以获得有关过度限制类型签名的警告吗?

    当我为可能更具多态性的函数提供类型签名时 GHC 或某些 lint 工具可以告诉我吗 GHC 不这样做 快速搜索 Hackage 也没有发现任何结果 实现这样的事情的一个简单但可能非常有效的方法是在 GHCi 中加载模块 使用 browse
  • 通过 Emacs 评估 ghci 或 Hugs 中的缓冲区

    在 Emacs 中使用 sml mode 我已经能够使用以下命令将缓冲区内容直接发送到较差的 SML 进程C c C b 现在我只想用 Haskell 做同样的事情 Haskell 模式似乎不支持这一点 所以我想知道 使用 Emacs 和
  • 如何在 Yesod 中使用 CSS 框架?

    我想将 Blueprint CSS 框架与 Yesod 一起使用 有没有最佳实践 因为 Yesod 使用 CSS 模板 所以在我看来我不能直接使用 css 文件 我必须将它们重命名为 lucius files 吗 如何将 CSS 添加到 d
  • Haskell Cabal 包 - 找不到 Paths_ 模块

    我正在开发一个 Haskell 项目 Happstack 服务器 Blaze HTML 前端作为主要库 我想添加一个静态数据目录 看起来你可以使用 Cabal 使用自动生成的Path
  • 在 Haskell 中计算移动平均线

    我正在学习 Haskell 所以我尝试实现移动平均函数 这是我的代码 mAverage Int gt Int gt Float mAverage x a fromIntegral k fromIntegral x k lt rawAvera
  • Haskell 类型系统的细微差别

    我一直在深入了解 haskell 类型系统的本质 并试图了解类型类的要点 我已经学到了很多东西 但我在下面的代码片段上遇到了困难 使用这些类和实例定义 class Show a gt C a where f Int gt a instanc
  • 将数据类型设置为 Kind * -> * 这不是函子

    布伦特 约尔吉类型分类百科全书 https www haskell org haskellwiki Typeclassopedia给出以下练习 举一个类型的例子 gt 不能将其制成 的实例Functor 不使用undefined 请告诉我什
  • Haskell:无法预期类型“Integer”与实际类型“Int”

    我已经盯着这段代码有一段时间了 但我无法理解该错误消息 divisors Integer gt Integer divisors n t t lt 1 n mod n t 0 length a gt Integer length 0 len
  • Haskell 中的 print 是纯函数吗?

    Is print在 Haskell 中是纯函数 为什么或者为什么不 我认为不是 因为它并不总是返回与纯函数应返回的值相同的值 类型的值IO Int并不是真正的Int 它更像是一张纸 上面写着 嘿 Haskell 运行时 请生成一个Int如此
  • 纯函数怎么能做IO呢?

    我最近了解到莫纳德随机数 http hackage haskell org package MonadRandom 0 1 13 docs Control Monad Random Class html t 3aMonadRandom图书馆
  • 如何在 Haskell 中向右或向左移动列表的 1 个元素?

    嗨 我一直在寻找答案 但找不到 假设我们有一个像这样的列表 1 10 4 5 3 我怎样才能将 5 向左移动 使这个列表变成 1 10 5 4 3 我尝试过了swapElementsAt通过找到该元素的索引 但它看起来非常不足 swapEl
  • 在 Yesod 生态系统中,对某些文本进行 urlencode 的最佳方式是什么?

    我想对一些文本进行 url 编码 例如 用 20 替换每个空格等 我找到了 HTTP Network HTTP Base urlEncode 并且可以使用它 但我想知道是否还有其他通常在 Yesod 生态系统中使用的东西 不幸的是 由于 U
  • 如何在 Haskell 中漂亮地打印表格?

    我想在 Haskell 中漂亮地打印一个类似表格的数据结构 列列表 例如 Table StrCol strings a bc c IntCol ints 1 30 2 DblCol doubles 2 0 4 5 3 2 应该渲染类似 st
  • Haskell 入门

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 几天来 我一直试图理解 Haskell 中的函数式编程范例 我通过阅读教程和观看截屏视频
  • Haskell / GHC - 是否有“警告不完整模式”的中缀标签/编译指示

    我正在寻找一个可以对特定的不完整模式发出警告的编译指示 它会使编译器失败并显示以下 假设的 代码 FAILIF incomplete patterns f Int gt Int f 0 0 我正在尝试使用 Arrows 编写一个 编译器 并

随机推荐

  • 按重复名称合并列表列表中的内容

    给定这样的列表列表 是否有一种优雅的方法将原始数据转换为已处理数据 我使用简单的值 如 1 2 3 但值可以是数据框或其他值 目标不是消除每个唯一名称的重复内容 而只是通过合并内容来消除重复名称 original structure lis
  • 如何使用fftw Guru界面

    我以前用过fftw plan dft用于多维傅里叶变换 fftw plan fftw plan dft int rank const int n fftw complex in fftw complex out int sign unsig
  • Angular 6 - Less CSS 的导入不再起作用

    我想重用 Angular 5 项目中使用 Less 的一些结构 在这个旧项目中我可以简单地加载 less在组件内使用此行的文件 import app shared less bootstrap 这将加载 my app src app sha
  • 如何解析 Inno Setup Pascal 脚本中的安装程序命令行开关值?

    当安装成功时 我试图从安装程序中触发 S2S 像素 像素需要一些详细信息 例如 IP 位置 时间和子 ID 我获得了除子 ID 之外的所有详细信息 子 ID 是在命令行上指定的 subID xxxx执行安装程序时进行切换 您可以使用 par
  • 无法删除 TableLayoutPanel 中控件之间的间距?

    我添加到我的按钮之间有一些间距TableLayoutPanel 我删除了按钮中的边框 并将面板中的边距和填充设置为 0 但我继续保持这种间距 tableLayoutPanel RowCount 设置为 8 并且Rows我添加了 8 行的集合
  • 从 ArrayList 中删除重复项

    我有一个自定义对象的 ArrayList 我想删除重复的条目 这些对象具有三个字段 title subtitle and id 如果某个副标题出现多次 我只需要带有该副标题的第一个项目 忽略带有该副标题的剩余对象 您可以使用自定义比较器将
  • ES6 通过 --experimental-modules 在 Node 中导入

    尝试在带有 experimental modules 标志的节点中使用 ES6 导入 具体来说 mkdir ma cd ma npm init npm i save moving averages touch index mjs 现在将以下
  • 为什么 es6 React 组件只能在“默认导出”下工作?

    该组件确实有效 export class Template extends React Component render return div component div export default Template 如果我删除最后一行
  • ID不能为空(自动递增)

    我正在为我的网站使用 INSERT ON DUPLICATE KEY 语句 它用于创建新闻项目 所以我想我可以使用相同的 MySQL 命令来创建和更新新闻项目 但是 当我使用以下内容时 INSERT INTO table id title
  • 蟒蛇海龟形状

    我正在用 pythonturtle 绘制一些东西 我使用了形状函数 但是形状在它们之前过度绘制了其他形状 我可以看到形状在移动 并且我只得到了最后一个形状 up goto 200 200 down shape circle shapesiz
  • 用于获取 VBA 中单击的 ActiveX 按钮名称的通用事件处理程序。

    所以我想知道是否可以引用被单击的按钮 所以我不必为每个按钮更改太多代码 这就是我所拥有的 Private Sub CommandButton1 Click Dim name As String With CommandButton1 If
  • 无法导入“联系表单 1”:无效的帖子类型 wpcf7_contact_form 无法导入媒体“db_site.sql_.txt”

    我是网络开发新手 特别是 WordPress 我使用 WordPress 作为 cms 框架创建了一个网站 我将数据库导入到我的 WordPress 仪表板中 一切都很顺利 但问题是某些内容从未成功导入 消息是这样的 无法导入媒体 db s
  • 循环遍历 data.table 并根据某些条件创建新列

    我有一个包含相当多列的 data table 我需要循环它们并使用某些条件创建新列 目前我正在为每一列编写单独的条件行 让我用一个例子来解释一下 让我们将示例数据视为 set seed 71 DT lt data table town re
  • 从另一种形式访问数据网格

    我在form1中有datagridview 如何从 form2 访问 datagridview private void button1 Click object sender EventArgs e string sql1 insert
  • “静态”startActivity(Intent) 方法?

    我有一个按钮 它的 View OnClickHandler 实现类从最近的 android app Activity 对象引用实例化了大约 3 个构造函数 单击时 我希望它打开位置设置面板 以便用户可以通过启动来启用 GPS 和 或基于网络
  • 如何控制活动流程 - 返回按钮与主页按钮

    我的申请中有 3 项活动 Activity1 gt Activity2 gt Activity3 在 Activity3 中 如果用户按 Back 我想返回到 Activity2 在Activity3的onPause事件中 我添加了一个fi
  • 找出两个长纪元值表示的两个日期之间的差异

    我的需要是我有一个 Long 值 它代表自纪元以来的毫秒值 我想找出那天和今天之间的天数差异 我正在使用Java8DAYS between inputDate currentDate 对于我使用过的 currentDateLocalDate
  • 如何让一个方法在后台持续运行直到程序结束?

    我想知道如何让方法在后台运行 IE 该方法在程序启动时启动 并持续执行其语句直到程序关闭 对于前 假设我有一个方法 gravity 它在程序运行时不断减少某个值 现在为了尝试这个 我使用以下程序 其中我试图在没有按下任何键时将公爵拉下来 重
  • pyspark 在一次加载中加载多个分区文件

    我正在尝试在一次加载中加载多个文件 都是分区文件 当我用 1 个文件尝试它时 它可以工作 但是当我列出 24 个文件时 它给了我这个错误 除了在加载后进行联合之外 我找不到任何有关限制的文档和解决方法 还有其他选择吗 下面的代码重现了问题
  • 解析 haskell 中的 Karva 表示法

    Karva 表示法在基因表达编程中用于表示数学表达式 看这里http www gene express programming com Tutorial002 asp 您可以通过读取基因并从左到右 从上到下填充节点来创建表达树 例如 在 1