几天前,我的一个朋友给了我一个Haskell问题

Hey, MK,假设我有个BNF,并且我在Haskell中有个这个BNF的parser。

现在,我想给这个BNF改一行,有没有办法不用动这个BNF parser的代码(因为是其他人写的),而是对这parser进行扩展呢?

这问题挺有趣的,也不算难。

这问题说是extensibility problem,其实有两个地方需要扩展。

0:Parser需要用open recursion之类的方法扩展

1:Parse出来的ADT也需要可扩展性

后半个需求见多了,Final Tagless,DTALC,Tree that grow,Recursion scheme style fix。。。于是放下不表,我们来处理前一个。

前半个。。Haskell's Overlooked Object System就搞过,当然他们有点heavy weight,打算随手弄一个超级轻量级的:5行就够了,多一行是小莎莎。

Ready?

1 data Object x = MkObject (x -> x)

1。Inheritance is not subtyping式的Object=recursive type。为了简易性(反正也不需要多高的扩展性)就不model真。recursive type,而只有recursive dependency。

1 use :: Object x ->x2 use (MkObject x) = let res = x res in res

2。3。最典型的tying the knot。其实就是fix了。

我们想想,这个x是什么variant的呢?covariant还是contravariant?

1 inherit :: (a -> b) -> (b -> a) -> Object a ->Object b2 inherit ab ba (MkObject aa) = MkObject (ab . aa . ba)

既然是invariant,那fmap contramap都用不上,但invariant依然能有map:两边一起传进来就行了。4。5。

这就是一个prototype based oo system了。

接下来讲怎么用哈:

1 test :: Object (Int, Int)2 test = MkObject $ \self -> (2, fst self + fst self)

这弄了个两个field的object,第零个field初始值为2(可能因为继承被override),第一个field为第零个field的值*2(不一定是3,如果任何field被override这个值都能改)。use test应该是(2, 4)。

1 inheritTest :: Object ((Int, Int), Int)2 inheritTest = inherit (\(l, r) -> ((l + 1, r + 2), r + 1)) fst test

这里继承了上面的Object,override了l(l + 1是super + 1),r被override到super + 2,加了个新的field,值是r+1。use inheritTest应该是((3, 8), 7)。记着传进来的参数不是self而是super就很好理解了。

好,open recursion搞好了,剩下的就是标准的final tagless了,体力活,没啥意思

1 classAST repr where2 lit :: Int ->repr3 plus :: repr -> repr ->repr4

5 classVar repr where6 var :: String ->repr7

8 type WholeParser repr =Parser repr9 type LitParser repr =Parser repr10 type PlusParser repr =Parser repr11

12 intP :: Parser Int13 intP = read many1 digit14

15 stringP :: Parser String16 stringP =many1 letter17

18 type OriginalParser repr =((LitParser repr, PlusParser repr), WholeParser repr)19 originalParser :: AST repr =>Object (OriginalParser repr)20 originalParser = MkObject $ \(~(_, p)) ->let21 litP = lit intP22 plusP = between (char '(') (char ')') (do {l plusP in24 ((litP, plusP), wholeP)25

26 type VarParser repr =Parser repr27 extendedParser :: (AST repr, Var repr) =>Object (VarParser repr, OriginalParser repr)28 extendedParser =inherit extend snd originalParser29 where30 extend ~((litP, plusP), wholeP) =let31 varP = var stringP in32 (varP, ((litP, plusP), varP wholeP))33

34 instance AST String where35 lit =show36 plus x y = "(" ++ x ++ " " ++ "+" ++ " " ++ y ++ ")"

37

38 instance Var String where39 var x = x

大功告成。

Q:封装呢?

A:Abstract Type is Existential Type

Q:这是prototype based的,class怎么办?

A:A Theory Of Object里面讲过怎么用prototype来做class

Q:多继承呢?

A:给定Object a,Object b,可以组合出Object (a, b),要菱形继承自己手动再inherit一下就好

Q:Subtyping?

A:Typeclass。

如果大家感兴趣,请评论下,我可以再写个blog把这些功能补完。

java中parser_愿你走出半生,归来仍是Java Parser相关推荐

  1. 愿你走出半生 归来仍是少年

    作者:碎瓦 链接:https://www.zhihu.com/question/57671944/answer/200362753 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  2. 给你的杭州旅游攻略-愿你走出半生,归来仍是姑娘

    给你的杭州旅游攻略 -- 愿你走出半生,归来仍是姑娘 来杭州玩,西湖不用说,你肯定要的去啦.但是周末和节假日,不懂的人玩的地方都是人山人海.所以为了避免看人头呢,你可以到人少的景点,比如: 首先推荐柳 ...

  3. Cocos2dx游戏教程(十五):“见缝插针”,愿你走出半生,归来仍是少年

    从决定写这个教程到第一个有戏教程结束也经历了好长时间,有的地方可能写的不好,也请大家多多包涵.决定写这个教程也是对自己学习的一个总结吧,写教程的过程也是自己学的过程. 一个小游戏所涉及到的知识点毕竟不 ...

  4. 愿你走出半生,归来仍是少年

    不知不觉已经走到了现在 这半年学习了java,做了一个官网.做了大米互助的第一版,目前小有改头换面之式的第二版也在筹划之中:感谢云姐.坤哥的信任,保证完成任务:筹划的过程中我们有一些因为理解不同,进度 ...

  5. java 异常 不抛,java中不捕获或抛出的异常

    java中不捕获或抛出的异常 发布时间:2020-06-25 14:29:16 来源:亿速云 阅读:137 作者:Leah 这期内容当中小编将会给大家带来有关java中不捕获或抛出的异常,文章内容丰富 ...

  6. 皓月天边,半步青莲。愿你把酒持剑,归来仍是少年。

    我还是像从前一样,冷漠不减,温柔用不上,狠心过了头. 多一点自知之明,少一点自作多情. 无法知道余生还要渡过多少不能被分担的漫漫长夜,无法知道我在那些漫漫长夜之后的黎明醒来想起这一段往事来,会是怎样的 ...

  7. Queue:愿你历尽千帆,归来仍是少年!

    成长的路上必然经历很多风雨 相信自己终有属于你的盛举 别因为磨难 停住你的脚步 坚持住 就会拥有属于你的蓝图 ---<少年> 1. Queue 特点 队列是一种特殊的线性表,是一种先进先出 ...

  8. 《愿你历尽千帆,归来仍是少年》-曾锴

    当时怀着好奇的心情买了这本书,读了这本书,最大的收获是认识了自己求学在外的意义,了解了作者在国外生活的经历,那是怀念家的感觉,求学不易,读书的用途.愿我们有缘今生,不忘初心,不负光阴,活出自我,终得精 ...

  9. java中bigdecimal除以int类型的数据怎么实现_大部分Java程序员都会忽略的几个问题,你中招没?...

    1. 正确使用 equals 方法 Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals. 举个例子: 运行上面的程序会抛出空指针异常,但是我们把第二行的条件 ...

最新文章

  1. 解决maven下载jar慢的问题(如何更换Maven下载源)
  2. SQL优化基础 使用索引(一个小例子)
  3. 说实话,你工作5年,不知道什么是Java agent技术,让我很吃惊...
  4. hyperv的安装与使用
  5. cf1556B B. Take Your Places!
  6. python如何提高程序可读性_提高Python的可读性?
  7. iOS之instancetype
  8. Spring框架 注解
  9. python之数据运算、字典、列表
  10. atitit 2017年学业计划 v5 r818.xlsx
  11. 分享一下好用的本地格式化软件hijson,这个居然还有人要收费才能下载,真是醉了
  12. 计算机随机数是如何生成的?(平分取中法、线性同余法)
  13. 如何查看硬盘对应的主板接口属性
  14. php中lpush(),lPush 命令/方法/函数
  15. 个人博客处理——页面处理
  16. 【精选】小白是如何挖漏洞的(技巧篇)
  17. MySQL 常见时间获取整理(当日、当月、当年、上一日、上一月、上一年,当月第一天,当年第一天等等)
  18. linux 修改mysql默认端口3306
  19. 【Linux】硬链接和符号链接(软连接)都可以修改原文件吗?--相同点与不同点
  20. playmaker按钮的效果

热门文章

  1. js 根据公历日期 算出农历_根据公历日期计算农历年生肖及公历转换农历的方法...
  2. m4v如何转换成mp4?用视频转换器转换很简单
  3. PID智能小车快速入门(一)
  4. 真心付出的一方失恋为什么痛,甚至厌世?
  5. UCF101数据集的处理问题
  6. NORDIC softDevice 蓝牙协议栈初始化程序分析(蓝牙从机,ble_peripheral)
  7. zabbix的搭建和简单使用
  8. 如何利用Framework模型生成IQD文件
  9. java入门,eclipse,spring boot… 新建springboot starter, 和 启动mnv srping-boot:run
  10. android音乐播放器的历史,基于Android音乐播放器的研究