HY编程快速入门实践课第二章 跟着python学HY

发布于:2024-06-21 ⋅ 阅读:(156) ⋅ 点赞:(0)

上一章: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.xfb.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的训练和推理工作!


网站公告

今日签到

点亮在社区的每一天
去签到