想在python里用lisp方言hy的目的:

1 用lisp去parse 包含 “数据+简单if控制流(代码、AST)”的配置文件,或者说用包含s-exp的.hy文件作为这类配置文件的实现(而不是用yml)

  以下引自编程珠玑徐宥的blog https://blog.youxu.info/2010/02/10/lisp-and-ai-2/

FORTRAN 基本上是围绕数组建立的,LISP 则是围绕链表实现的。通过研究下棋,几何题等 AI 问题的表示,我们的读者不难发现, AI 研究关心于符号和逻辑计算远大于数值计算,比如下棋,就很难抽象成一个基于纯数字的计算问题。 这样,只能存数字的数组就显得不适合。 当然我们可以把数组扩展一下,让这些数组元素也可以存符号。不过即使这样,数组也不能做到存储不同结构的数据。 比方说棋类中,车马炮各有各自的规则,存储这些规则需要的结构和单元大小都不一样,所以我们需要一个存储异构数据单元的模块,而不是让每个单元格的结构一样。 加上在AI 中,一些数据需要随时增加和修改的。 比如国际象棋里,兵第一步能走两步,到底部又能变成皇后等等,这就需要兵的规则能够随时修改,增加,删除和改变

当时几乎所有的研究者,把宝押在了实现一个通用的符号演算系统上,...... LISP 通过函数式编程来完成了这些演算规则的构建。

这里,需要提请读者注意的是, LISP 的全称是 LISt Processing, 即列表处理,但实际上 LISP 是由两种互相正交的哲学组合形成的, 一个是列表处理,另一个是函数式编程。 虽然在下面以后,我们会介绍 S-Expression 这样美妙的把两者无缝结合在一起的形式,但是为了清晰我们的概念,我要强调一下列表处理和函数式编程是两个正交的部分。实际上,我们完全可以用其他的不是函数的方式构建一个列表处理语言。

最最直接的通过图灵测试的方法不是让计算机和人脑一样思考,而是只要能够让计算机处理对话中用到的的单词,句子和符号

即使计算机拥有了对符号的操作能力,通过了图灵测试,它也未必是是“有智能”的。

什么语言适合人工智能的问题,就变成了“什么语言能做符号处理”。这个问题的答案,读者也都猜到了,就是 LISP。

S-Expression。 这个 S,其实就是 Symbolic 的意思。 把程序数据都统一的当成符号。LISP 支持 meta-programming。LISP 程序可以处理,生成和修改 LISP 程序。这个特性,加上函数是一阶对象的特性,使得 LISP 远远比同时代的任何语言灵活。

   其实,如果仅仅是“列表处理”和“函数式编程”,python都基本够了 。不对齐的数据有list dict  读json,yml也挺方便;对齐的矩阵有pandas的DataFrame。

    lisp的真正威力来自S表达式,最简洁直观地显式表达了AST,也便于灵活修改AST,这对定制DSL特别有用

作为一种编程语言的语法,S表达式到处都是括号是挺恶心的,远不如python的缩进简洁;

作为一种数据结构的表达   S表达式虽然比不上yml简洁,  但其实和json的到处是"" :和{}, C系列的 {} 相同,而比XML和HTML的<></>强太多了;

但而作为代码数据合一的AST的表达,S表达式是独一无二地精炼的表示法!!

   也许AI领域 在小数据的统计学习,和大数据的NN连接主义网络角度看, 这种基于规则推导和符号演算,动态修改替换AST的符号主义AI研究风潮早已远去。可以说市场需求极度萎缩了。过时很久很久了,也没有啥前途

但作为某些领域的配置文件,数据代码没法截然分开的领域(其实领域驱动设计不就是追求充血模型吗?2333),

只要需求里有这样的交互步骤:

1领域专家编写规则(in DSL)

2系统parse规则、修改AST(in S-exp)、求值,返回函数或数值

那么lisp仍然有一席之地,基于S表达式的符号演算,仍然是最佳选择。

2 python对Unicode字型作为变量名/函数名的标识符(identifier)有限制,只能用能表示成文字的(英文、希腊文字母,中文汉字),其他符号无法作为标识符。这对基于符号的规则描述DSL是一个极大的阻碍。尤其是其他流行语言都支持无限制的unicode符号做变量和函数名的情况下(C C#  Java Clojure)

(各种语言对Unicode字符作为函数名和变量的支持情况汇总:https://rosettacode.org/wiki/Unicode_variable_names

这是python刻意而为的,因此只能靠其他语言来实现了https://www.python.org/dev/peps/pep-3131/  (大意是unicode太新了,python不是编译到中间语言 RTL(Register Transfer Language)的语言...blabla)

综合上面这两点理由的交集,显然就是hy最合适了。

看着hy的官方文档 http://docs.hylang.org/en/stable/language/index.html

和learnXin minute Y https://learnxinyminutes.com/docs/hy/

还有就是github的issue  https://github.com/hylang/hy/issues

但是,作为一个只看了《SICP》的lisp纯新手,实验了1天,各种不适应。

首先 要 用 -> 实现 形如 (->  x  (/ 2)  (np.ceil)) 这样的级联调用,一点也不容易。

都是小坑,但串联起来真要命。

1  构造 单参数函数

np.ceil 必须用closure封一个函数。不能直接用(.ceil np),因为这时np已经成了第一个operand,x是要作为第二个operand了,需要->> 了,但是前面的(/ 2)还是需要->

而且用 . 也不行 。(. np method)  method只能是symbol写死 (图中注释掉的方式), 不能用输入fname解析为方法名。

要构造单操作数的函数  目前只能用python自己的getattr 方法

相当于

def get_f_in_np(fname):
if hasattr(np, fname):
   return np.getattr(fname)
else:
return lambda x:x

2  理解HyExpression

当import一个包含s-expression的hy文件,或者在py中用hy提供的read_str方法读入1段包含s表达式的字符串的时候

    input_str = "(* 2)"
expr = hy.read_str(input_str)

此时的expr是一个符合python中AST的 HyExpression:或者HyList( 如果输入是'[(1,2)]'的话)

可以看到,得到的expr并不是纯lisp的“代码是数据,数据是代码”,或者说“code/data皆symbol”。

因为hy是把s表达式解释为python AST,所以得到的是Hy定义的Expression Symbol Int String  ... 大约和python基本数据类型对应吧。

这也就可以理解,python是一种“动态,但强类型(Strongly Typed”的语言。

而lisp 是 “动态+弱类型(Weakly Typed)”的语言  ——引自《Fluent Python》

虽然 “()”是对应 HyExpression的 , "((XXX))" ,每多一层(),expr就会多一层HyExpression([ ...]) 嵌套,

但在hy中,我们不能直接用括号对HyExpression 直接求值:

(expr  x)

会提示 HyExpression  is not callable  其实是HyXXX 都是 not callable 的。

那么,可以采用绕弯的方法:利用“macro那一套:”。

回到lisp本来的概念:圆括号()表示对里面的S表达式求值(正则序,或者应用序),

而用macro的话,可以代入,但不求值。(这样,才方便对AST的修改,否则都是直接求值完了)。

既然用无法用() 对HyXXX求值,那么 要从(/ 2) 生成一个fn 或者 用 ->求值 可

`反引号 表示 返回一个不求值的S表达式

~波浪号表示 展开、带入求值结果 。 只能在`反引号 内使用

然后,利用(eval  ) 对这个式子求值,就OK了。

用的是defn 和fn  并没有用defmacro 但想法和做法都是macro的,代换求值模型和基于macro的AST修改是lisp的精髓之一。

注意,必须是(eval  `()) 直接(`()) 是不行的:

3 函数级联调用时的comp与#*

如果在python中,我们构造了list_fn = [f1, f2]  两个单参数的函数,

希望 在hy里用函数式的方法,得到一个新函数F(x) =  f2(f1(x)) 返回给py

这样,hy发挥了函数/算符的工厂的角色。

那么应该怎么做呢? 首先官方文档的里有comp http://docs.hylang.org/en/master/language/core.html

是这样的

comp

Usage: (comp f g)

Compose zero or more functions into a new function. The new function will chain the given functions together, so ((comp g f) x) is equivalent to (g (f x)). Called without arguments, comp returns identity.

=> (setv example (comp str +))
=> (example 1 2 3)
"6" => (setv simple (comp))
=> (simple "hello")
"hello"

注意 comp后面跟的不是 list 而是  两个单摆浮搁的函数

如果送进list_fn 应该怎么玩,整个官方文档没有说,我在issue里问,作者只给出了#*  也没说怎么用,然后就说要问去stackoverflow和maillist问

好吧,我试了试,总算搞定了。

3个注意点:

1 用 #* 就完成了对列表的解包(为什么不写进文档!)

2 要实现按list顺序依次调用,要先用python的reversed函数对list_fn进行颠倒。

3 因为我们要返回函数,所以直接() 就可以了, 不用再搞一次(fn [x] )

——哈哈,一共2行代码,居然有3个要点,前2少了任何1条,都写不出来,导致昨天卡了我很久。

现在看看,其实作为函数工厂真的比python还简洁呢。没有return,最后一个()直接就返回了。也不需要fn [x]  来代表lambda x:

4 没有cons  car cdr

导致我看《SICP》过来,一开始极端不适应。

而且比较坑的是,这些关键词本来之前hy一直有,但在最新版0.15 hy大幅度精简了关键词,这些本来有的东西全都给删除掉了

car   first

cdr   rest

cons 直接没有了。说是可以用list代替

好吧,其实解决了1-3,这第4倒不是太严重。但之前的一些教程,回帖,google返回的官网文档快照,都还有cons car cdr这些,导致了很大的迷惑性。

5 显示s-exp的字面值

如果直接print 显示的都是

如果我修改了表达式,然后想assert期望的结果,比较这个太不直观了

在文档里找了半天,才找到http://docs.hylang.org/en/master/contrib/hy_repr.html

而且是hy下的,用法也不直观。在python下,这样用

from hy.contrib.hy_repr import hy_repr

input_rule_list = '["												

python + lisp hy的新手注记1的更多相关文章

  1. python + lisp hy的新手注记2 eval, HyModel and python AST

    来自我在Stack Overflow上的提问,https://stackoverflow.com/questions/51675355/how-to-eval-a-cond-case-and-retu ...

  2. CentOS-7.4(1708)release notes发行注记

    Red Hat Enterprise Linux 当前的最新版本是 7.3. Red Hat Enterprise Linux 7 当前仅支持 64 位CPU:64-bit AMD.64-bit In ...

  3. ArcGIS中的标注和注记

    在ArcMap中可以使用标注和注记来识别要素,选择标注或注记取决于你需要如何控制文本显示以及在ArcMap中如何存储文本. 1.标注只是临时显示相关数据或字段 2.标注用于长时间保存数据以及显示方式. ...

  4. 关于arcgis engine的注记显示与关闭问题

    1.注记的添加需要拿到IGeoFeatureLayer接口下的AnnotationProperties属性,转为IAnnotationLayerPropertiesCollection接口,并创建一个 ...

  5. 【ESRI论坛6周年征文】ArcEngine注记(Anno/ Label/Element等)处理专题 -入门篇

    原发表于ESRI中国社区,转过来.我的社区帐号:jhlong http://bbs.esrichina-bj.cn/ESRI/viewthread.php?tid=122097 ----------- ...

  6. 创建文本注记TextElement

    1.创建一个字体 /// <summary> /// 字体设置 /// </summary> /// <param name="size">Th ...

  7. 创建线注记LineElement

    1.根据2点创建一条线 /// <summary> /// 创建线 /// </summary> /// <param name="pnt1"> ...

  8. ArcMap 标注、注记、图形文本

    标注.注记.图形文本 2016年8月10日10:29 ArcMap中怎样向地图添加文本,其中标注与注记是重点内容,此处对此进行总结. 参考链接: ①地图文本基本词汇: 什么是文本? ArcGIS 提供 ...

  9. 【ArcEngine入门与提高】Element(元素)、Annotation(注记)旋转

    因项目需要,需要做一个旋转注记的工具.因为注记这玩意用的比较少,网上资源也很少,所以做起来相当头疼.在经过一番研究之后,终于搞清楚注记的存储原理了,原来是和Element的类似,只不过注记是要把Ele ...

随机推荐

  1. kivy 使用webview加载网页

    from kivy.app import App from kivy.uix.widget import Widget from kivy.clock import Clock from jnius ...

  2. MySQL5.7 的新特点

    1.安全性 MySQL 5.7 的目标是成为发布以来最安全的 MySQL 服务器,其在 SSL/TLS 和全面安全开发方面有一些重要的改变. mysql.user表结构升级 MySQL5.7用户表my ...

  3. linux时间修改-hwclock和date

    修改系统时间date 设定日期:date -s 月/日/年,例如设定日期为2018年12月1日,date -s 12/01/2018(年也可以是两位) 设定时间:date -s hh:mm:ss,例如 ...

  4. Vue基础进阶 之 Vue生命周期与钩子函数

    Vue生命周期 Vue生命周期:Vue实例从创建到销毁的过程,称为Vue的生命周期: Vue生命周期示意图:https://cn.vuejs.org/v2/guide/instance.html#生命 ...

  5. Django之URL控制器(路由层)

    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), 一.视图层路由配置系统 URL配置(URLconf)就像Django ...

  6. 《学习OpenCV3》第14章课后习题

    1.在一条含有 N 个点的封闭轮廓中,我们可以通过比较每个点与其它点的距离,找出最外层的点.(这个翻译有问题,而且这个问题是实际问题) a.这样一个算法的复杂度是多少? b.怎样用更快的速度完成这个任 ...

  7. cJSON库的简单介绍及使用

    转载:http://www.cnblogs.com/liunianshiwei/p/6087596.html JSON 语法是 JavaScript 对象表示法语法的子集.数据在键/值对中:数据由逗号 ...

  8. (转)Awesome GAN for Medical Imaging

    Awesome GAN for Medical Imaging 2018-08-10 09:32:43 This blog is copied from: https://github.com/xin ...

  9. Install and Compile MatConvNet: CNNs for MATLAB --- Deep Learning framework

    Install and Compile MatConvNet: CNNs for MATLAB --- Deep Learning framework 2017-04-18  10:19:35 If ...

  10. 【C#】扩展方法浅谈

    C#3 引入的扩展方法这一个理念. 扩展方法最明显的特征是在方法参数中第一个参数有this声明. 其实C#库中有很多已经是扩展方法了.比如linq中对序列使用的查询语句, where, select等 ...