Julia语言中的元编程

news2024/11/15 9:02:51

在 Julia 语言中,元编程(Metaprogramming)可以生成或操作其他代码。这种技术允许程序员在编译时或运行时动态地创建、修改或分析代码,从而增强语言的功能和灵活性,以宏(Macros)、表达式和符号(Expressions and Symbols)、反射(Reflection)、并行计算(Parallel Computing)为主。在运行以下代码时需要先下载DataFrames包和DataFramesMeta包。

定义表达式

在Julia中,表达式通常表现为 :() ,可以使用parse()函数将字符串转换为表达式:

#parse()函数将字符串转换为表达式
str = "12-3"
ex1 = Meta.parse(str)

 使用dump()函数可以查看表达式的构造:
 

ex2 = :(5 + 6)
dump(ex2)

Julia也可以用表达式的构造定义表达式:

ex3 = Expr(:call, :+, 4, 8)

 表达式求值

使用 eval() 函数可以对表达式求值:
 

a = 10
b = 12
c = 5

ex1 = :(1 + 5)
ex2 = :(2 + a)
ex3 = :(b - 3)
ex4 = :(a + b - c)
ex5 = :(6 * a + b / 4 - c ^ 2)

println("ex1 = ", eval(ex1))
println("ex2 = ", eval(ex2))
println("ex3 = ", eval(ex3))
println("ex4 = ", eval(ex4))
println("ex5 = ", eval(ex5))

运行结果

 

宏编程

 Julia 中的宏允许你在编译时生成或变换代码。它们以 @ 符号开头,接收 Julia 表达式作为输入,并返回一个新的表达式,这个新表达式将在宏调用的位置替换原始代码。宏在 Julia 中非常强大,但也需要谨慎使用,因为它们可能会使代码更难理解和调试。

以下代码定义一个宏来打印问候信息。

macro sayhi(name)  
    :(println("Hi ", $name, "!"))  
end  
  
@sayhi "AliBaba"

 

数据框中的宏

这里我使用的Jupyter工具,和钱师傅一样使用的Julia版本是1.6.7。

先使用 DataFrames包 建立一个数据框:

using DataFrames  
  
mya1 = ["大B哥", "十三妹", "山鸡", "陈浩南", "大天二", "刘老二"]  
mya2 = ["女", "男", "女", "女", "男", "男"]  # 使用方括号创建数组  
mya3 = [12, 11, 14, 9, 8, 13]  
mya4 = [94, 86, 72, 88, 79, 81]  
mya5 = ["A", "B", "C", "A", "A", "C"]  
  
# 使用 DataFrame 构造函数创建数据框  
studf1 = DataFrame(姓名=mya1, 性别=mya2, 年龄=mya3, 成绩=mya4, 评级=mya5)  
  
# 显示数据框  
println(studf1)

运行结果

 

接下来使用三种宏来对其中的数据进行操作

#where宏已弃用,更改为subset宏用于查询
using DataFramesMeta
println(@subset(studf1, :成绩 .> 90))

println(@subset(studf1, :成绩 .> 60, :成绩 .< 92, :年龄 .> 10))
#with宏
#所有学生成绩-2
new_data = @with(studf1, :成绩 .- 2) 
println(new_data)

#所有学生成绩*1.2
println(@with(studf1, :成绩 .* 1.2))

#让所有男生成绩+5
studf2 = @subset(studf1, :性别 .== "男")
println(@with(studf2, :成绩 .+ 5))

运行结果

#select宏,用来指定列
println(@select(studf1, :姓名))
#显示姓名、年龄、评级
println(@select(studf1, :姓名, :年龄, :评级))

 运行结果

并行计算 

在Julia语言中,并行计算采用协程任务来进行多个计算之间的切换,可以使用Channel()函数来表示轻量线程之间的执行顺序

#每行代码分开运行


#建立管道
c1 = Channel(36)
c2 = Channel{Int32}(30)
#向管道写入内容
put!(c1, 3)
put!(c2, 15)
take!(c1)
take!(c2)
#关闭Channel管道, 关闭之后只能读取,无法写入
close(c1)
close(c2)

Julia语言的 Channel() 函数和R语言的管道运算符 %>%  有相似的地方,都是提供了一种方式来处理和传递数据:它们都允许数据在不同的操作或任务之间流动,但 Channel() 主要用于并发编程。

 以上内容Markdown版本代码

---

**ExpressionSearch**:

创建数学表达式并对其进行求值。利用Julia语言中的宏编程可以在代码中动态地计算数值。

首先,我们定义了三个变量 `a`、`b` 和 `c`,并分别给它们赋值为 10、12 和 5。


```julia
a = 10
b = 12
c = 5
```
接下来,我们将创建几个数学表达式。这些表达式并不是立即计算的,而是被存储为可以稍后求值的对象。

我们使用 `:` 符号来创建所谓的“引用表达式”或“符号表达式”。这意味着表达式内的变量和运算不会被立即计算,而是保持原样。


```julia
ex1 = :(1 + 5)      
ex2 = :(2 + a)  
ex3 = :(b - 3)     
ex4 = :(a + b - c) 
ex5 = :(6 * a + b / 4 - c ^ 2)  
```
现在,我们有五个待求值的表达式。要计算这些表达式的值,我们使用 `eval()` 函数。这个函数会“评估”或“计算”给定的表达式,并返回结果。


```julia
println("ex1 = ", eval(ex1))  # 输出 ex1 的计算结果
println("ex2 = ", eval(ex2))  # 输出 ex2 的计算结果,以此类推
println("ex3 = ", eval(ex3))
println("ex4 = ", eval(ex4))
println("ex5 = ", eval(ex5))
```
当运行这段代码时,可以看到每个表达式的计算结果被打印出来。

---
---

**Macro**:

定义一个宏来打印问候信息。


```julia
macro sayhi(name)  
    :(println("Hi ", $name, "!"))  
end
```
在这里,我们定义了一个名为 `sayhi` 的宏。这个宏接受一个参数 `name`,然后返回一个在编译时会展开的表达式。这个表达式的作用是打印一条包含 `name` 的问候信息。

注意宏定义中的 `:(...)` 语法,它用来创建一个表达式对象。在这个表达式中,我们可以使用 `$name` 来插入宏参数 `name` 的值。这样,在宏展开时,`$name` 就会被替换为实际的参数值。

现在,我们已经定义了 `sayhi` 宏,接下来让我们看看如何使用它。


```julia
@sayhi "AliBaba"
```
使用宏时,我们需要在宏名前面加上 `@` 符号,然后跟上宏的参数。在这个例子中,我们调用 `sayhi` 宏,并传入字符串 `"AliBaba"` 作为参数。当这段代码被执行时,宏会在编译时展开,生成一条打印 `"Hi AliBaba!"` 的语句。

---

**接下来使用Julia的DataFrames包和Channel函数来展示数据操作和管道操作**


**第一部分:使用 DataFrames 创建和显示数据框**

首先,我们导入了 `DataFrames` 包,这是 Julia 中用于数据处理和分析的一个强大工具。通过它,我们可以创建数据框(DataFrame),这是一种二维的、大小可变的、可以存储多种类型数据的表格结构。

我们创建了五个数组,分别代表姓名、性别、年龄、成绩和评级,然后使用这些数组作为列创建了数据框 `studf1`。最后,我们打印出这个数据框的内容。

```julia

using DataFrames  
  
mya1 = ["大B哥", "十三妹", "山鸡", "陈浩南", "大天二", "刘老二"]  
mya2 = ["女", "男", "女", "女", "男", "男"]  # 使用方括号创建数组  
mya3 = [12, 11, 14, 9, 8, 13]  
mya4 = [94, 86, 72, 88, 79, 81]  
mya5 = ["A", "B", "C", "A", "A", "C"]  
  
# 使用 DataFrame 构造函数创建数据框  
studf1 = DataFrame(姓名=mya1, 性别=mya2, 年龄=mya3, 成绩=mya4, 评级=mya5)  
  
# 显示数据框  
println(studf1)


```

**第二部分:使用 DataFramesMeta 进行数据查询**

接下来,我们导入了 `DataFramesMeta` 包,它提供了一系列宏来简化数据框的查询和操作。我们使用 `@subset` 宏来筛选出满足特定条件的数据行。首先,我们筛选出成绩大于 90 的学生,然后筛选出成绩在 60 到 92 之间且年龄大于 10 的学生。

```julia

#where宏已弃用,更改为subset宏
using DataFramesMeta
println(@subset(studf1, :成绩 .> 90))

println(@subset(studf1, :成绩 .> 60, :成绩 .< 92, :年龄 .> 10))

```


**第三部分:使用 DataFramesMeta 进行数据转换**

`DataFramesMeta` 还提供了 `@with` 宏来进行数据转换。我们首先将所有学生的成绩减去 2,然后将所有学生的成绩乘以 1.2。接着,我们筛选出所有男生,并将他们的成绩加上 5。

```julia

#with宏
#所有学生成绩-2
new_data = @with(studf1, :成绩 .- 2) 
println(new_data)

#所有学生成绩*1.2
println(@with(studf1, :成绩 .* 1.2))

#让所有男生成绩+5
studf2 = @subset(studf1, :性别 .== "男")
println(@with(studf2, :成绩 .+ 5))

```

**第四部分:使用 DataFramesMeta 选择特定列**

使用 `@select` 宏,我们可以轻松地选择数据框中的特定列。我们首先选择了姓名列,然后选择了姓名、年龄和评级三列。

```julia

#select宏,用来指定列
println(@select(studf1, :姓名))

#显示姓名、年龄、评级
println(@select(studf1, :姓名, :年龄, :评级))

```

**第五部分:Julia 中的 Channel 用法**

展示Julia 中 `Channel` 的基本用法。`Channel` 是 Julia 中用于并发编程的一种数据结构,它可以在不同的任务(或线程)之间安全地传递数据。我们创建了两个 `Channel`,分别用于存储不同类型的数据。然后,我们向这两个通道中写入了一些数据,并读取了这些数据。最后,我们关闭了这两个通道。需要注意的是,一旦通道被关闭,就无法再向其中写入数据,但仍然可以从中读取之前写入的数据。

```julia

#建立管道
c1 = Channel(36)
```

```julia

c2 = Channel{Int32}(30)
```


```julia

#向管道写入内容
put!(c1, 3)
```

```julia

put!(c2, 15)
```

```julia

take!(c1)
```

```julia

take!(c2)
```

```julia

#关闭Channel管道, 关闭之后只能读取,无法写入
close(c1)
```

```julia

close(c2)
```

Julia的`Channel()`函数和R语言的管道运算符`%>%`虽然在表面上看似不同,但实际上都涉及到了数据流和顺序操作的概念。然而,它们的设计目标、使用方式和功能特性存在显著的区别。

**Julia的`Channel()`函数**

Julia的`Channel()`函数用于创建一个通道,这个通道可以被多个任务(或线程)用来进行同步通信。这是一个并发编程中的常见模式,用于在不同的任务之间安全地传递数据。通道可以被看作是一个队列,任务可以在通道上发送(`put!`)或接收(`take!`)消息。

**R语言的管道运算符`%>%`**

R语言的管道运算符`%>%`,来源于`magrittr`包,后被集成到`tidyverse`系列包中,用于将一个对象的输出作为下一个函数的输入。这是一种函数式编程的技巧,可以让代码更加清晰、易读。使用管道运算符,你可以将多个函数操作链接在一起,形成一个流畅的操作链。

**相同功能**

虽然它们的实现方式和应用场景不同,但从某种程度上说,Julia的`Channel()`和R语言的管道运算符都提供了一种方式来处理和传递数据:它们都允许数据在不同的操作或任务之间流动。

**不同点**

1. **并发与顺序**:Julia的`Channel()`主要用于并发编程,允许在不同的任务之间进行数据交换和同步。而R语言的管道运算符则主要是用于顺序编程,将一个函数的输出作为下一个函数的输入。
2. **同步与异步**:在Julia中,通道可以用于同步操作,即一个任务在发送或接收消息时可能会等待直到另一个任务准备好。而在R中,管道运算符的操作是顺序且同步的,每个函数都会在前一个函数完成后立即执行。
3. **编程范式**:Julia的`Channel()`更符合并发编程范式,而R语言的管道运算符则更符合函数式编程范式。
4. **错误处理**:在Julia中,如果通道被关闭或发生错误,发送和接收操作可能会引发异常。而在R中,管道运算符的错误处理通常依赖于每个函数的错误处理机制。
5. **数据流向**:在Julia中,数据可以通过通道在多个任务之间双向流动。而在R中,数据通过管道运算符只能单向流动,即从左到右。
6. **类型安全**:Julia是一种类型安全的语言,通道的使用需要明确的类型匹配。而在R中,管道运算符的使用更加灵活,不同类型的对象可以通过管道进行传递和处理(尽管这可能会导致运行时错误)。

---

 

 

 

 

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

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

相关文章

【python报错】Intel MKL FATAL ERROR: Cannot load mkl/../../../libmkl_rt.so.2.

python报错&#xff1a; Intel MKL FATAL ERROR: Cannot load mkl/../../../libmkl_rt.so.2.在切换旧版numpy版本的时候&#xff0c;出现了这个报错&#xff0c;表现就是将numpy切换到<1.24的版本的时候&#xff0c;只要import numpy就弹出以上报错。 尝试了网上的各种方法…

【Go语言】Go语言中的流程控制

Go语言中的流程控制 流程控制主要用于设定计算执行的顺序&#xff0c;简历程序的逻辑结果&#xff0c;Go语言的流程控制语句与其他语言类似&#xff0c;支持如下几种流程控制语句&#xff1a; 条件语句&#xff1a;用于条件判断&#xff0c;对应的关键字有if、else和else if&a…

STM32-ADC一步到位学习手册

1.按部就班陈述概念 ADC 是 Analog-to-Digital Converter 的缩写&#xff0c;指的是模拟/数字转换器。它将连续变量的模拟信号转换为离散的数字信号。在 STM32 中&#xff0c;ADC 具有高达 12 位的转换精度&#xff0c;有多达 18 个测量通道&#xff0c;其中 16 个为外部通道&…

搜索算法(算法竞赛、蓝桥杯)--DFS单词接龙

1、B站视频链接&#xff1a;B20 DFS 单词接龙_哔哩哔哩_bilibili 题目链接&#xff1a;[NOIP2000 提高组] 单词接龙 - 洛谷 #include <bits/stdc.h> using namespace std; const int N25; int n,ans; int used[N];//每个单词的使用次数 string word[N];void dfs(string…

姓名若有孤寡数,极不利婚姻!

易经云“同声相应&#xff0c;同气相求”&#xff0c;一个人的名字会形成一个磁场&#xff0c;在个人的生活当中会影响到自己的方方面面&#xff0c;如运势、事业工作、桃花运等&#xff0c;同时也会影响自己的感情婚姻哦。 峰民曾经在办公室接待了一位女士&#xff0c;看了她…

备战蓝桥杯---状态压缩DP进阶题1

我们来看一看一道比较难的问题&#xff08;十分十分的巧妙&#xff09;&#xff1a; 显然我们应该一行一行放&#xff0c;又竖的会对下一行产生影响&#xff0c;我们令横着放为0&#xff0c;竖着放的上方为1. 对于下一行&#xff0c;前一行放1的下面为0&#xff0c;但是会出现…

C++:内存管理|new和delete

创作不易&#xff0c;感谢三连支持&#xff01; 一、内存分布 为什么需要内存管理呢&#xff1f;&#xff1f;因为我们在程序的运行过程中会需要各种各样的数据&#xff0c;而我们根据数据的不同存储在不同的区域里面&#xff0c;是为了更高效地处理数据。而C语言相比Java来说…

知识图谱1——neo4j

2024年要搞知识图谱&#xff0c;因此没有办法&#xff0c;只能将我之前固守的JDK1.8&#xff0c;升级到JDK21&#xff0c;因为JDK21也是LTS版本&#xff0c;neo4j高版本就不支持JDK8&#xff0c;因此没有办法&#xff0c;只有升级了。写这篇只是一个搭建笔记&#xff0c;我的初…

【Qt学习】QSpinBox 与 QDateTimeEdit 控件 的介绍与实例()

文章目录 QSpinBox1.1 介绍1.2 实例使用 - &#xff08;模拟点餐-功能扩充&#xff09;1.3 资源文件 2. QDateTimeEdit2.1 介绍2.2 使用&#xff08;计算时间差值 / 间隔&#xff09;daysTo() 与 secsTo() 2.3 资源文件 QSpinBox 1.1 介绍 对于QSpinBox&#xff0c;我们可以查…

OSI七层模型/TCP四层模型

协议&#xff1a; 协议是双方共同指定的一组规则&#xff0c;在网络通信中表示通信双方传递数据和解释数据的一组规则。 从A上传文件到服务器B,需要在A和B之间制定一个双方都认可的规则&#xff0c;这个规则就叫文件传输协议&#xff0c;该协议是ftp协议的一个初级版本&#…

JavaScript练手小技巧:一文看懂<script>标签的 ansyc 和 defer

<script>标签的 ansyc 和 defer 属性。只对外部加载 JS 文件有效。 <script src"js/app.js" async></script> <script src"js/app.js" defer></script> 普通加载 js&#xff08;同步加载&#xff09;&#xff1a;会打断 …

uview2中上传文件和若依前后端分离配合的代码

uview2中的上传文件需要配合着自己后端的上传的代码 uview2 代码&#xff1a; uploadFilePromise(url) {return new Promise((resolve, reject) > {// 后续自己封装let a uni.uploadFile({//自己的请求路径url: that.$baseURL /uploadAvater, //上传的文件filePath: tha…

leetcode hot100 每日温度

在本题中&#xff0c;我们是通过单调栈来解决的&#xff0c;因为我们采用了栈的数据结构&#xff0c;并且&#xff0c;栈内存储的元素是单调的。 本题我们考虑&#xff0c;将气温数组元素的下标存入栈中&#xff0c;首先初始化要把0放入&#xff0c;0是下标的意思。然后我们拿…

诊所门诊电子处方软件操作教程及试用版下载,医务室处方笺管理系统模板教程

诊所门诊电子处方软件操作教程及试用版下载&#xff0c;医务室处方笺管理系统模板教程 一、前言 以下软件程序教程以 佳易王诊所电子处方软件V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 如上图&#xff0c;点击基本信息设置——处方配…

【JavaEE进阶】 代理模式

文章目录 &#x1f343;前言&#x1f38b;什么叫代理模式&#x1f334;静态代理&#x1f38d;动态代理&#x1f6a9;JDK动态代理&#x1f6a9;CGLIB动态代理 ⭕总结 &#x1f343;前言 前面对Spring AOP的详细使用进行了介绍&#xff0c;这篇博客博主将详细讲解一下Spring AOP…

使用统一功能完善图书管理系统

目录 一、前提 二、实现强制登陆传统方式 三、拦截器 1、概念 2、拦截器 &#xff08;1&#xff09;定义拦截器 &#xff08;2&#xff09;注册拦截器 &#xff08;3&#xff09;运行 3、使用拦截器实现强制登陆 4、DispatcherServlet源码解析 四、适配器模式 1、适…

深入剖析k8s-控制器思想

引言 本文是《深入剖析Kubernetes》学习笔记——《深入剖析Kubernetes》 正文 控制器都遵循K8s的项目中一个通用的编排模式——控制循环 for {实际状态 : 获取集群中对象X的实际状态期望状态 : 获取集群中对象X的期望状态if 实际状态 期望状态 {// do nothing} else {执行…

协议-http协议-基础概念03-http状态码-http特点-http性能-压缩和分块传输-范围请求

参考来源&#xff1a; 极客时间-透视HTTP协议(作者&#xff1a;罗剑锋)&#xff1b; 01-状态码分类 开头的 Version 部分是 HTTP 协议的版本号&#xff0c;通常是HTTP/1.1&#xff0c;用处不是很大。后面的 Reason 部分是原因短语&#xff0c;是状态码的简短文字描述&#xff…

【计算机网络_应用层】TCP应用与相关API守护进程

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 相关使用接口2. 代码实现2.1 日志组件2.2 Server端2.3 Client端2.3 bug解决 3. 守…

c语言数据结构(5)——栈

欢迎来到博主的专栏——C语言数据结构 博主id&#xff1a;代码小豪 文章目录 栈栈的顺序存储结构栈的插入空栈的初始化栈的删除判断空栈读取栈顶元素数据 实现顺序栈的所有代码栈的链式存储结构链式栈的初始化链式栈的入栈操作链式栈的出栈操作 实现链式栈的所有代码 栈 栈是…