想在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. An Example of How Oracle Works

    Oracle是怎么工作的,摘自Oracle 9i的官方文档 The following example describes the most basic level of operations tha ...

  2. css盒子模型、边框border、外边距margin、填充padding、轮廓outline

    盒子模型:盒子默认的宽度为容器的宽度,也可以自省设定宽度,高度根据内容适应,也可以自行设定高度.min-height设定最小高度 一个盒子包括外边距.边框.内边距和实际内容 Margin(外边距):清 ...

  3. spring使用@Value标签读取.properties文件的中文乱码问题的解决

    最近测试某个老系统的时候,启动的时候发@Value注入的中文是乱码,文件使用GBK/UTF-8的时候均会出现乱码问题,但是spring配置文件里面注入的占位符并没有这个问题,bean文件设置了file ...

  4. Win7的话,可能有十种简单的方法进行提速呢

    1.窗口转换更快速 Windows7绚丽的效果的确美观,但漂亮的效果就需要拿速度来交换,因此如果你想要Windows7中的各个窗口切换得更快速,那关闭窗口最大.最小化的动画效果后,你会发现窗口切换得更 ...

  5. 【Python56--爬取妹子图】

    爬取网站的思路 第一步:首先分析爬取网站的连接地址特性,发现翻页图片的时候连接:http://www.mmjpg.com/mm/1570  ,http://www.mmjpg.com/mm/1569, ...

  6. topcoder srm 698 div1 -3

    1.定义重复串$S=T+T$,即$S$可以表示成一个串的叠加.给定一个串$s$,可以通过删除字符.修改字符.增加字符来使得其变为重复串.问最少的次数. 思路:首先将$s$分成个串$s_{0},s_{1 ...

  7. Linux 使用statvfs读取文件系统信息

    本文转载自:https://blog.csdn.net/papiping/article/details/6980573 在测试过程中,f_bfree的值比f_frsize的值大于10%的尺寸大小,意 ...

  8. [转] Java 基础

    1. 面向对象和面向过程的区别 面向过程 面向对象 2. Java 语言有哪些特点 3. 关于 JVM JDK 和 JRE 最详细通俗的解答 JVM JDK 和 JRE 4. Oracle JDK 和 ...

  9. C# 截取 byte 字节 转字符串

    byte[] byteArray = System.Text.Encoding.Default.GetBytes(content); Byte[] ThisByte = new Byte[1];Buf ...

  10. 4-Five-Youth

      ①People are always talking about 'the problem of youth'. If there is one--which I take leave to do ...