上一章:HY编程快速入门实践课第一章 初步了解-CSDN博客
本章学习参考文档:Tutorial — Hy 0.29.0 manual
API reference — Hy 0.29.0 manual
结合Python 学习HY运算符
Python 提供了各种二进制和一元运算符。这些通常在 Hy 中使用同名的核心宏调用:例如, (+ 1 2)
调用名为 +
的核心宏,它使用 Python 的加法运算符,名称相同,但也有一些例外:
在python中 | 在HY中 |
== | = |
~ | bnot |
is not |
is-not |
not in |
not-in |
=> (= 2 2)
True
=> (bnot 2)
-3
=> (is-not 2 3)
stdin-c58e627a30c9bc185544b4633354f008e331afdf:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
(is-not 2 3)
True
=> (not-in "a" ["a" "b"])
False
其它诸如+ - * / and not 等都跟python非常类似
=> (+ 1 2)
3
=> (- 1 2)
-1
=> (* 2 3)
6
=> (/ 3 2)
1.5
=> (^ 3 2) ;异或
1
=> (** 3 2)
9
=> (% 3 2)
1
=> (% 7 3)
1
=> (and 1 0)
0
=> (or 0 1 )
1
=> (<= 1 2)
True
对于python的切片,HY里面有get和cut来实现
=> x
"Hello World"
=> (get x 0)
"H"
=> (get x 3)
"l"
=> (cut x 1 4)
"ell"
=> (cut x -1 )
"Hello Worl"
=> (cut x -1 -5 -1)
"dlro"
=> (cut x 2 None)
"llo World"
=> (cut x 3 5)
"lo"
=> (cut x -3 None)
"rld"
=> (cut x 0 None 2)
"HloWrd"
正式开始HY编程实践
现在,让我们正式开始HY的编程实现吧
打印和运算
=> (print "Hy, world!")
Hy, world!
=> (+ 1 3)
4
=> (- (* (+ 1 3 88) 2) 8)
176
跟其它语言很不同的就是使用括号将程序体扩起来,以及前置运算符。
注释和设置变量
HY的注释从一个 ; 字符开始,一直持续到行尾。注释在功能上等同于空格,设置变量使用setv:
=> (setv zone-plane 8) ; setv 设置变量
get和cut获取元素
使用以下命令 get
访问列表、字典或其他数据结构的元素:
(setv fruit ["apple" "banana" "cantaloupe"])
(print (get fruit 0)) ; => apple
(setv (get fruit 1) "durian")
(print (get fruit 1)) ; => durian
使用cut访问有序结构中的一系列元素:
(print (cut "abcdef" 1 4)) ; => bcd
逻辑判断和循环
条件逻辑可以用以下命令 if
构建:
(if (= 1 1)
(print "Math works. The universe is safe.")
(print "Math has failed. The universe is doomed."))
if语句后面跟三部分,第一部分是判断,判断True则执行第二部分,否则执行第三部分。注意到此为止,我们碰到的都是单句,即每一部分都是一条语句。如果想用复合语句应该怎么办呢?
可以使用do语句,它可以将多条单句组成复合语句
(if (do (print "Let's check.") (= 1 1))
(do
(print "Math works.")
(print "The universe is safe."))
(do
(print "Math has failed.")
(print "The universe is doomed.")))
分支语句,使用cond
(setv somevar 33)
(cond
(> somevar 50)
(print "That variable is too big!")
(< somevar 10)
(print "That variable is too small!")
True
(print "That variable is jussssst right!"))
wiile和for循环
(setv x 3)
(while (> x 0)
(print x)
(setv x (- x 1))) ; => 3 2 1
(for [x [1 2 3]]
(print x)) ; => 1 2 3
除了for迭代,还可以使用lfor进行迭代,两者的区别就是for迭代没有返回,而lfor会返回包含元素的列表
(print (lfor x [1 2 3] (* x 2))) ; => [2, 4, 6]
函数、类和模块
使用defn定义函数
(defn fib [n]
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
(print (fib 8)) ; => 21
使用df定义匿名函数
(print (list (filter (fn [x] (% x 2)) (range 10))))
参数列表的特殊符号
参数列表中 defn
fn
的特殊符号允许您指示可选参数、提供默认值和收集未列出的参数:
(defn test [a b [c None] [d "x"] #* e]
[a b c d e])
(print (test 1 2)) ; => [1, 2, None, 'x', ()]
(print (test 1 2 3 4 5 6 7)) ; => [1, 2, 3, 4, (5, 6, 7)]
[c None]
:这是一个带有默认值的参数。如果调用函数时没有提供c
的值,它将默认为None
(在 Hy 中与 Python 的None
相对应)。[d "x"]
:与[c None]
类似,但这次d
的默认值是字符串"x"
。#* e
:这是一个收集剩余参数的特殊语法。所有在d
之后传递给函数的参数都将作为一个元组(tuple)赋值给e
。
函数调用时可以用冒号+参数名来设定参数
(test 1 2 :d "y") ; => [1, 2, None, 'y', ()]
使用defclass定义类
(defclass FooBar []
(defn __init__ [self x]
(setv self.x x))
(defn get-x [self]
self.x))
创建一个新实例 fb
FooBar
并通过各种方式访问其属性:
(setv fb (FooBar 15))
(print fb.x) ; => 15
(print (. fb x)) ; => 15
(print (.get-x fb)) ; => 15
(print (fb.get-x)) ; => 15
请注意,语法 fb.x
和 fb.get-x
仅在被调用的对象(在本例中为 fb
)是简单的变量名称时才有效。要获取任意形式的 FORM
属性或调用方法,必须使用 (. FORM x)
语法 或 (.get-x FORM)
或 调用 getattr()
。
访问外部模块
访问外部模块,无论是用 Python 还是 Hy 编写的,都使用 import
:
(import math)
(print (math.sqrt 2)) ; => 1.4142135623730951
还可以使用一次性导入语法 hy.I
:
(print (hy.I.numpy.ndarray [2 3]))
[[0. 0. 0.]
[0. 0. 0.]]
Python 可以像任何其他模块一样导入 Hy 模块,只要 Hy 本身是先导入的,当然,如果你正在运行 Hy 程序,这肯定已经发生了。
使用defmacro定义宏
宏是 Lisp 的基本元编程工具。宏是在编译时(即,当 Hy 程序被转换为 Python ast
对象时)调用并返回代码的函数,代码成为最终程序的一部分。下面是一个简单的示例:
(print "Executing") (defmacro m [] (print "Now for a slow computation") (setv x (% (** 10 10 7) 3)) (print "Done computing") x) (print "Value:" (m)) (print "Done executing")
(setv x (% (** 10 10 7) 3))的计算量较大,计算机会有明显的计算时间卡顿。在交互模式下执行上面语句每次都需要较长时间,且输出一样。将内容写入testmacro.hy文件后,执行hy testmacro.hy2次,会发现两次执行的输出不一样,且第二次执行的时间大大缩短
(py310) [skywalk@x250 ~/work/lisp]$ hy testmacro.hy
Now for a slow computation
Done computing
Executing
Value: 1
Done executing
(py310) [skywalk@x250 ~/work/lisp]$ hy testmacro.hy
Executing
Value: 1
Done executing
究其原因,就是第一次执行时是编译执行,(setv x (% (** 10 10 7) 3))会花费大量时间,第二次执行则是省去编译时间,也就是在宏里的这三句的时间全都节省出来了:
(print "Now for a slow computation")
(setv x (% (** 10 10 7) 3))
(print "Done computing")
而这,正是Lisp的与其它所有语言不同的奥秘。而且其它语言一旦支持了宏,也就变成了Lisp的一种方言,成为Lisp家族的一份子。
推荐使用的库
Hyrule
Hyrule 是 Hy 的标准实用程序库。它提供了各种函数和宏,可用于编写 Hy 程序。
使用Hyrule库的时候,需要在python环境安装hyrule库:
pip install pyrule
(import hyrule [inc])
(list (map inc [1 2 3])) ; => [2 3 4]
(require hyrule [case])
(setv x 2)
(case x 1 "a" 2 "b" 3 "c") ; => "b"
toolz和cytoolz
toolz 及其 Cython 变体 cytoolz 为函数式编程和使用可迭代对象提供了许多实用程序。
当然也需要提前安装tooz库
pip install toolz
(import toolz [partition])
(list (partition 2 [1 2 3 4 5 6])) ; => [#(1 2) #(3 4) #(5 6)]
Metadict
Metadict 允许您将字典的元素引用为属性。当经常将具有常量字符串的元素引用为键时,这很方便,因为普通索引在 Hy 中有点冗长。
(import metadict [MetaDict])
(setv d (MetaDict))
(setv d.foo 1) ; i.e., (setv (get d "foo") 1)
d.foo ; i.e., (get d "foo")
; => 1
(list (.keys d))
; => ["foo"]
飞桨PaddlePaddle人工智能训练推理库
图穷匕现了同志们,咱就是为了飞桨才整的这期HY学习实践系列。飞桨是非常流行的人工智能训练和推理框架,易于使用,执行效率高,用过的都说好!首先还是安装飞桨:
pip install paddlepaddle
这里用cpu版本来做例子,如果安装gpu等版本请参考飞桨官网:
飞桨PaddlePaddle-源于产业实践的开源深度学习平台
下面是一个简单的HY代码的飞桨训练例子,业内独一份啊!
(import paddle)
(import paddle.vision.transforms [ToTensor])
;(paddle.set_device "gpu")
(pys "train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=ToTensor())")
(setv test-dataset (paddle.vision.datasets.MNIST :mode 'test :transform (ToTensor)))
(setv lenet (paddle.vision.models.LeNet))
; Mnist inherits from paddle.nn.Layer which is a Net, and model includes training functionality
(setv model (paddle.Model lenet))
; Set the optimizer, loss, and metric needed to train the model
(model.prepare
(paddle.optimizer.Adam :learning_rate 0.001 :parameters (model.parameters))
(paddle.nn.CrossEntropyLoss)
(paddle.metric.Accuracy :topk [1 2])
;(paddle.metric.Accuracy :topk (1 2))
)
; Start training
(model.fit train-dataset :epochs 2 :batch-size 64 :log-freq 400)
; Start evaluation
(model.evaluate test-dataset :log-freq 100 :batch-size 64)
它竟然能开始训练!!太激动了!
在上一次AI浪潮,Lisp语言扮演了重要的角色。在这一次AI浪潮里,Lisp开始像种子一样发芽啦!
总结
HY是跟python最亲近的Lisp,有python基础的同学们学起来会感觉尤其亲切。
HY的两大特点,也就是Lisp的两大特点:
- 1 括号+前置运算符
- 2 宏
HY可以导入各种python库,所以也就可以导入飞桨库,进行AI的训练和推理工作!