Julia 元编程

Julia 把自己的代码表示为语言中的数据结构,这样我们就可以编写操纵程序的程序。

元编程也可以简单理解为编写可以生成代码的代码。

元编程(英语:Metaprogramming),是指某类计算机程序的编写,这类计算机程序编写或者操纵其它程序(或者自身)作为它们的资料,或者在编译时完成部分本应在运行时完成的工作。多数情况下,与手工编写全部代码相比,程序员可以获得更高的工作效率,或者给与程序更大的灵活度去处理新的情形而无需重新编译。

编写元程序的语言称之为元语言。被操纵的程序的语言称之为"目标语言"。一门编程语言同时也是自身的元语言的能力称之为"反射"或者"自反"。

-- 维基百科

Julia 源代码执行阶段

1、解析原始 Julia 代码: Julia 解析器首先将解析字符串以获得抽象语法树(AST),AST 是一种结构,它以易于操作的格式包含所有代码。

2、执行已解析的 Julia 代码:: 在这个阶段,执行已解析的 Julia 代码。

当我们在交互式编程环境(REPL)中输入代码并按回车键时,会执行以上两个阶段。

使用元编程工具,我们就可以访问这两个阶段之间的 Julia 代码,即在源代码解析之后,但在执行之前。

程序表示

Julia 提供了一个 Meta 类,其中可以用 Meta.parse(str) 来对一个字符串进行解析,用 typeof(e1) 返回 Expr:

实例

julia> prog = "1 + 1"
"1 + 1"
julia> ex1 = Meta.parse(prog)
:(1 + 1)

julia> typeof(ex1)
Expr

返回 :(1 + 1) , 这个返回的值由一个冒号和后面的表达式组成,用 typeof(ex1) 返回 Expr。

Expr 对象包含两个部分(ex1 包含了 head 和 args 属性):

一个标识表达式类型的符号对象。

实例

julia> ex1.head
:call

另一个是表达式的参数,可能是符号、其他表达式或字面量:

实例

julia> ex1.args
3-element Vector{Any}:
  :+
 1
 1

表达式也可能直接用 Expr 构造:

实例

julia> ex2 = Expr(:call, :+, 1, 1)
:(1 + 1)

上面构造的两个表达式:一个通过解析构造,一个通过直接构造,两个是等价的:

实例

julia> ex1 == ex2
true

Expr 对象也可以嵌套:

实例

julia> ex3 = Meta.parse("(4 + 4) / 2")
:((4 + 4) / 2)

我们也可以使用 Meta.show_sexpr 查看表达式,以下实例展示了嵌套的 Expr:

实例

julia> Meta.show_sexpr(ex3)
(:call, :/, (:call, :+, 4, 4), 2)

符号

我们可以通过冒号 : 前缀运算符存储一个未计算但已解析的表达式。

实例

julia> ABC = 100
100

julia> :ABC
:ABC

引用下面的整个表达式:

实例

julia> :(100-50)
:(100 - 50)

引用算数表达式:

实例

julia> ex = :(a+b*c+1)
:(a + b * c + 1)

julia> typeof(ex)
Expr

注意等价的表达式也可以使用 Meta.parse 或者直接用 Expr 构造:

实例

julia>      :(a + b*c + 1)       ==
       Meta.parse("a + b*c + 1") ==
       Expr(:call, :+, :a, Expr(:call, :*, :b, :c), 1)
true

引用多个表达式也可以在 quote ... end 中包含代码块。

实例

julia> ex = quote
           x = 1
           y = 2
           x + y
       end
quote
    #= none:2 =#
    x = 1
    #= none:3 =#
    y = 2
    #= none:4 =#
    x + y
end

julia> typeof(ex)
Expr

执行表达式

表达式解析后,我们可以使用 eval() 函数来执行:

实例

julia> ex1 = :(1 + 2)
:(1 + 2)

julia> eval(ex1)
3

julia> ex = :(a + b)
:(a + b)

julia> eval(ex)
ERROR: UndefVarError: b not defined
[...]

julia> a = 1; b = 2;

julia> eval(ex)
3

抽象语法树 (AST)

抽象语法树 (AST) 是一种结构,是源代码语法结构的一种抽象表示。

它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

我们可以在 dump() 函数查看表达式的层次结构:

实例

julia> dump(:(1 * cos(pi/2)))
Expr
   head: Symbol call
   args: Array{Any}((3,))
      1: Symbol *
      2: Int64 1
      3: Expr
         head: Symbol call
         args: Array{Any}((2,))
            1: Symbol cos
            2: Expr
               head: Symbol call
               args: Array{Any}((3,))
                  1: Symbol /
                  2: Symbol pi
                  3: Int64 2

插值

使用值参数直接构造 Expr 对象虽然很强大,但与 Julia 语法相比,Expr 构造函数可能让人觉得乏味。作为替代方法,Julia 允许将字面量或表达式插入到被引用的表达式中。表达式插值由前缀 $ 表示。

在此示例中,插入了变量 a 的值:

实例

julia> a = 1;

julia> ex = :($a + b)
:(1 + b)

对未被引用的表达式进行插值是不支持的,这会导致编译期错误:

julia> $a + b
ERROR: syntax: "$" expression outside quote

在此示例中,元组 (1,2,3) 作为表达式插入到条件测试中:

julia> ex = :(a in $:((1,2,3)) )
:(a in (1, 2, 3))

在表达式插值中使用 $ 是有意让人联想到字符串插值和命令插值。表达式插值使得复杂 Julia 表达式的程序化构造变得方便和易读。

宏提供了一种机制,可以将生成的代码包含在程序的最终主体中。 宏将一组参数映射到返回的 表达式,并且生成的表达式被直接编译,而不需要运行时 eval 调用。 宏参数可能包括表达式、字面量和符号。

这是一个非常简单的宏:

实例

julia> macro sayhello()
           return :( println("Hello, world!") )
       end
@sayhello (macro with 1 method)

宏在Julia的语法中有一个专门的字符 @ (at-sign),紧接着是其使用 macro NAME ... end 形式来声明的唯一的宏名。在这个例子中,编译器会把所有的 @sayhello 替换成:

:( println("Hello, world!") )

当 @sayhello 在REPL中被输入时,解释器立即执行,因此我们只会看到计算后的结果:

julia> @sayhello()
Hello, world!

现在,考虑一个稍微复杂一点的宏:

实例

julia> macro sayhello(name)
 return :( println("Hello, ", $name) )
 end
@sayhello (macro with 1 method)

这个宏接受一个参数 name。当遇到 @sayhello 时,quoted 表达式会被展开并将参数中的值插入到最终的表达式中:

实例

julia> @sayhello("human")
Hello, human

我们可以使用函数 macroexpand 查看引用的返回表达式:

实例

julia> ex = macroexpand(Main, :(@sayhello("human")) )
:(Main.println("Hello, ", "human"))

julia> typeof(ex)
Expr

我们可以看到 "human" 字面量已被插入到表达式中了。

还有一个宏 @ macroexpand,它可能比 macroexpand 函数更方便:

实例

julia> @macroexpand @sayhello "human"
:(println("Hello, ", "human"))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux磁盘管理

磁盘管理 基本分区管理 磁盘划分思路 进入分区表,新建分区更新分区表格式化分区表挂载使用 #lsblk #df -h 查看设备挂载情况 #fdisk -l 设备分区情况 #fdisk /dev/sdb 添加一块硬盘,需要将其分两个分区,分别格式化成ext4和vfat格式文件系…

Shell脚本学习-for循环结构2

案例:通过脚本实现仅sshd、rsyslog、crond、network、sysstat服务在开机时自启动。 Linux系统在开机的服务通常工作在文本模式3级别,因此只需要查找3级别以上的开启的服务即可。查看命令: chkconfig --list |grep 3:on [rootvm1 ~]# chkco…

安卓camera1设置自动连续对焦

需求 camera 1实现的控制摄像头拍照功能. adb控制自动拍照,发现近点时拍照很模糊,需要自动连续对焦. mCamera.autoFocus(null) 这个接口只能实现单次对焦.不适用. 代码 private Parameters mParameters;p…

TechTool Pro for mac(硬件监测和系统维护工具)

TechTool Pro 是为 Mac OS X 重新设计的全新工具程序,不但保留旧版原有的硬件侦测功能,还可检查系统上其他重要功能,如:网络连接,区域网络等。 TechTool Pro for mac随时监控和保护您的电脑,并可预设定期检…

最新SecureCRT 中文注册版

SecureCRT是一款由VanDyke Software公司开发的终端仿真软件,它提供了类似于Telnet和SSH等协议的远程访问功能。SecureCRT专门为网络管理员、系统管理员和其他需要保密访问网络设备的用户设计。 软件下载:SecureCRT for ma注册版 远程访问:Sec…

MySQL 与MongoDB区别

一、什么是MongoDB呢 ? MongoDB 是由C语言编写的,是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB 将数据存储为一…

【PHP代码审计】ctfshow web入门 php特性 93-104

ctfshow web入门 php特性 93-104 web 93web 94web 95web 96web 97web 98web 99web 100web 101web 102web 103web 104 web 93 这段PHP代码是一个简单的源码审计例子,让我们逐步分析它: include("flag.php");: 这行代码将flag.php文件包含进来。…

【机器学习】西瓜书学习心得及课后习题参考答案—第6章支持向量机

笔记心得 6.1 间隔与支持向量—— w w w是法向量,垂直与超平面 w T x b 0 w^Txb0 wTxb0。这一节了解了支持向量机的基本型。 min ⁡ w , b 1 2 ∣ ∣ w ∣ ∣ 2 s . t . y i ( w T x i b ) ≥ 1 , i 1 , 2 , . . . , m . \min_{w,b} \frac{1}{2}||w||^2 \\ s.…

如何建立含有逻辑删除字段的唯一索引

业务场景 在实际工作当中,遇到一个场景,就是在用户注册时,名字要全局唯一,当然,我们是可以对用户进行删除的,你会怎么去做? 分析 一般来说,我们可以在用户注册请求时&#xff0c…

习题1.27

先写代码 (defn square [x] (* x x)) (defn expmod[base exp m](cond ( exp 0) 1(even? exp) (mod (square (expmod base (/ exp 2) m)) m):else (mod (* base (expmod base (- exp 1) m)) m)))(defn fermat-test[n](defn try-it [a](cond ( a n) (println "test end&qu…

极狐GitLab 全新「价值流仪表盘」使用指南

本文来源:about.gitlab.com 作者:Haim Snir 译者:极狐(GitLab) 市场部内容团队 GitLab / 极狐GitLab 价值流仪表盘的使用相对简单,这种可以定制化的仪表盘能够让决策者识别数字化转型进程中的趋势及机遇。 如果你已经在用 GitLab…

Android学习之路(1) App工程的项目结构

一、App工程的项目结构 1.项目下面有两个分类 一个是app(代表app模块),另一个是Gradle Scripts。其中app下面又有3个子目录,其功能说明如下: manifests 子目录下面只有一个XML文件,即AndroidManifest.xmljava子目录,…

谈谈量子计算技术

目录 1.什么是量子计算 2.量子计算的应用领域 3.量子计算对现代科学的影响 4.量子计算未来的发展趋势 1.什么是量子计算 量子计算是一种基于量子力学原理的计算方法,利用量子比特(Quantum Bit,简称qubit)而不是经典计算中的比特…

ES6学习-Promise

Promise 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。 语法上: Promise 是一个对象,从它可以获取异步操作的消息。 特点 对象的状态不受外界影响。Promise 对象戴白哦一个异步操…

shell 脚本

一、使用PID过滤该进程的所有信息 #! /bin/bash # Function: 根据用户输入的PID,过滤出该PID所有的信息 read -p "请输入要查询的PID: " P nps -aux| awk $2~/^$P$/{print $11}|wc -l if [ $n -eq 0 ];thenecho "该PID不存在!&#xff0…

MobPush Android SDK 厂商推送限制

概述 厂商推送限制 每个厂商通道都有对应的厂商配额和 QPS 限制,当请求超过限制且已配置厂商回执时,MobPush会采取以下措施: 当开发者推送请求超过厂商配额时,MobPush将通过自有通道进行消息下发。当开发者推送请求超过厂商 QP…

【雕爷学编程】Arduino动手做(184)---快餐盒盖,极低成本搭建机器人实验平台

吃完快餐粥,除了粥的味道不错之外,我对个快餐盒的圆盖子产生了兴趣,能否做个极低成本的简易机器人呢?也许只需要二十元左右 知识点:轮子(wheel) 中国词语。是用不同材料制成的圆形滚动物体。简…

C#开发FFMPEG例子(API方式) FFmpeg推送udp组播流

代码及工程见https://download.csdn.net/download/daqinzl/88156926 开发工具:visual studio 2019 播放,可采用ffmpeg工具集里的ffplay.exe, 执行命令 ffplay udp://238.1.1.10:6016 也可以参考(C#开发FFMPEG例子(API方式) FFmpeg拉取udp组播流并播放)…

【雕爷学编程】Arduino动手做(186)---WeMos ESP32开发板9

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&#x…

Flutter游戏引擎Flame系列笔记 - 1.Flame引擎概述

Flutter游戏引擎Flame系列笔记 1.Flame引擎概述 - 文章信息 - Author: 李俊才(jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132119035 【介绍】…