├── .npmrc ├── .gitignore ├── README.md ├── vercel.json ├── netlify.toml ├── package.json ├── pages ├── multiple-entries.md ├── comonicon.md ├── configurations.md └── expronicon.md ├── .github └── workflows │ └── deploy.yml ├── components └── Counter.vue ├── slides.md └── slides.old.md /.npmrc: -------------------------------------------------------------------------------- 1 | # for pnpm 2 | shamefully-hoist=true 3 | auto-install-peers=true 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | *.local 5 | index.html 6 | .remote-assets 7 | components.d.ts 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Julia中文社区2022年会报告 2 | 3 | 请复制以下命令配置这个报告的幻灯片 4 | 5 | ```sh 6 | npm install 7 | npx slidev 8 | ``` 9 | 10 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "rewrites": [ 3 | { "source": "/(.*)", "destination": "/index.html" } 4 | ], 5 | "buildCommand": "npm run build", 6 | "outputDirectory": "dist" 7 | } 8 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build.environment] 2 | NODE_VERSION = "14" 3 | 4 | [build] 5 | publish = "dist" 6 | command = "npm run build" 7 | 8 | [[redirects]] 9 | from = "/*" 10 | to = "/index.html" 11 | status = 200 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "juliacn2022", 3 | "private": true, 4 | "scripts": { 5 | "build": "slidev build", 6 | "dev": "slidev --open", 7 | "export": "slidev export" 8 | }, 9 | "dependencies": { 10 | "@slidev/cli": "^0.37.1", 11 | "@slidev/theme-apple-basic": "^0.20.0", 12 | "@slidev/theme-default": "*", 13 | "@slidev/theme-seriph": "*", 14 | "xterm": "^5.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pages/multiple-entries.md: -------------------------------------------------------------------------------- 1 | # Multiple Entries 2 | 3 | You can split your slides.md into multiple files and organize them as you want using the `src` attribute. 4 | 5 | #### `slides.md` 6 | 7 | ```markdown 8 | # Page 1 9 | 10 | Page 2 from main entry. 11 | 12 | --- 13 | src: ./subpage.md 14 | --- 15 | ``` 16 | 17 |
18 | 19 | #### `subpage.md` 20 | 21 | ```markdown 22 | # Page 2 23 | 24 | Page 2 from another file. 25 | ``` 26 | 27 | [Learn more](https://sli.dev/guide/syntax.html#multiple-entries) 28 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy pages 2 | on: push 3 | jobs: 4 | deploy: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: actions/setup-node@v2 9 | with: 10 | node-version: '14' 11 | - name: Install dependencies 12 | run: npm install 13 | - name: Install slidev 14 | run: npm i -g @slidev/cli 15 | - name: Build 16 | run: slidev build --base JuliaCN2022Talk 17 | - name: Deploy pages 18 | uses: crazy-max/ghaction-github-pages@v2 19 | with: 20 | build_dir: dist 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /components/Counter.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 38 | -------------------------------------------------------------------------------- /slides.md: -------------------------------------------------------------------------------- 1 | --- 2 | # try also 'default' to start simple 3 | theme: apple-basic 4 | # random image from a curated Unsplash collection by Anthony 5 | # like them? see https://unsplash.com/collections/94734566/slidev 6 | # background: https://source.unsplash.com/collection/94734566/1920x1080 7 | # apply any windi css classes to the current slide 8 | class: 'text-center' 9 | # https://sli.dev/custom/highlighters.html 10 | highlighter: shiki 11 | # show line numbers in code blocks 12 | lineNumbers: false 13 | # some information about the slides, markdown enabled 14 | info: | 15 | ## 罗秀哲的工具箱 16 | 我将介绍我开发的三个在社区里相对受欢迎的工具的使用用例和工作原理:为命令行界面设计的Comonicon, 17 | 为元编程设计的Expronicon以及为配置文件以及Schema文件设计的Configurations。 18 | 19 | # persist drawings in exports and build 20 | drawings: 21 | persist: false 22 | # use UnoCSS 23 | css: unocss 24 | layout: intro 25 | --- 26 | 27 | # 罗秀哲的开源工具箱 28 | 29 | Expronicon, Comonicon 和 Configurations 30 | 31 | --- 32 | 33 | 34 | 35 | --- 36 | src: pages/expronicon.md 37 | --- 38 | 39 | --- 40 | src: pages/configurations.md 41 | --- 42 | 43 | --- 44 | src: pages/comonicon.md 45 | --- 46 | 47 | -------------------------------------------------------------------------------- /pages/comonicon.md: -------------------------------------------------------------------------------- 1 | # Comonicon 2 | 3 | 命令行界面生成器 4 | 5 | ## 功能 6 | 7 | - 定义命令行界面 8 | - 基础版本 9 | - 命令行工程 10 | - 将配置文件变成命令行界面 11 | - 产生对应shell的自动补全 12 | - 打包并配置命令行程序 13 | 14 | --- 15 | layout: two-cols 16 | --- 17 | 18 | # 定义命令行界面 19 | 20 | 尽管Comonicon的实现要比前几个包更加复杂,但是它的使用更加简单, 21 | 你只需要知道两个宏 `@cast` 和 `@main`, 右边是一个极简的例子 22 | 23 | 24 | 25 | 更加详细的使用方法请参考我在JuliaCon2022的演讲,由于时间原因 26 | 我们将不在这里讨论Comonicon的使用 27 | 28 | 29 | 30 | 31 | 32 | ::right:: 33 | 34 | ```julia 35 | """ 36 | ArgParse example implemented in Comonicon. 37 | 38 | # Arguments 39 | 40 | - `x`: an argument 41 | 42 | # Options 43 | 44 | - `--opt1 `: an option 45 | - `-o, --opt2 `: another option 46 | 47 | # Flags 48 | 49 | - `-f, --flag`: a flag 50 | """ 51 | @main function main(x; opt1=1, opt2::Int=2, flag=false) 52 | println("Parsed args:") 53 | println("flag=>", flag) 54 | println("arg=>", x) 55 | println("opt1=>", opt1) 56 | println("opt2=>", opt2) 57 | end 58 | ``` 59 | 60 | --- 61 | 62 | ## 基于Expronicon的代码生成器 63 | 64 | Comonicon是一个从Julia表达式到多种其它语言的代码生成器 65 | 66 | ```mermaid {theme: 'neutral', scale: 0.8} 67 | graph TD 68 | Julia --> ComoniconIR; 69 | ComoniconIR --> JuliaCLI; 70 | ComoniconIR --> ZSH; 71 | ComoniconIR --> BASH; 72 | ComoniconIR --> Other; 73 | ``` 74 | 75 | 而这个package本身也以编译器的方式进行设计, 76 | 这使得我们可以添加很多很有用,但是非常符合直觉的功能。 77 | 78 | --- 79 | layout: two-cols 80 | --- 81 | 82 | ## 和Configurations一起使用 83 | 84 | 很多机器学习,或者数值模拟任务里需要大量进行不用参数的实验, 85 | 这个时候拥有**一个配置文件**会非常方便对实验进行记录, 86 | 但是同时我们会有需要**部分调整配置文件参数的需要**。 87 | 88 | Comonicon作为一个编译器能够理解被`@option`定义的类型 89 | 从而将其转化为对应的命令行界面 90 | 91 | ```sh 92 | ➜ Comonicon git:(main) ✗ julia --project main.jl run --config.c=2 93 | config = OptionB(OptionA(2, 2), 2) 94 | ``` 95 | 96 | ::right:: 97 | 98 | ```julia 99 | using Comonicon 100 | using Configurations 101 | 102 | @option struct OptionA 103 | a::Int = 2 104 | b::Int = 2 105 | end 106 | 107 | @option struct OptionB 108 | option::OptionA = OptionA() 109 | c::Int 110 | end 111 | 112 | """ 113 | # Options 114 | 115 | - `-c, --config `: config. 116 | """ 117 | @cast function run(;config::OptionB) 118 | @show config 119 | end 120 | 121 | @cast function rundef(;config::OptionA=OptionA()) 122 | @show config 123 | end 124 | 125 | @main 126 | ``` -------------------------------------------------------------------------------- /pages/configurations.md: -------------------------------------------------------------------------------- 1 | # Configurations 2 | 3 | 配置文件(configuration)和数据模式(schema)工具箱 4 | 5 | ## 功能 6 | 7 | - 定义一个数据模式(schema)或者配置文件 8 | - 解析数据模式 9 | - 利用类型转换来验证数据模式 10 | - 从数据模式到代码生成 11 | 12 | --- 13 | layout: two-cols 14 | --- 15 | 16 | ## 定义一个数据模式(schema)或者配置文件 17 | 18 | 我们这里以TOML为例(Julia标准库自带了一个解析器),便携一个 19 | 关于Julia编译器选项的配置文件,尖括号 `<>` 里表示对应参数的 20 | 类型和名称。 21 | 22 | ```toml 23 | [julia] 24 | compile="" 25 | threads="" 26 | optimize="" 27 | startup="" 28 | ``` 29 | 30 | 31 | 32 | 为了方便处理并检测输入是否正确,我们往往会定义其**对应的类型** 33 | 从而能够在语言里表示这样一个配置文件 34 | 35 | ```julia 36 | struct JuliaOptions 37 | compile::String # yes or no 38 | threads::Int 39 | optimize::Int 40 | startup::String 41 | end 42 | ``` 43 | 44 | 45 | 46 | ::right:: 47 | 48 | 49 | 50 | 接下来我们将需要把从解析器里的输出结果转换到我们的 51 | 结构体 `JuliaOptions` 并且检查输入的值是否符合 52 | 要求,例如 `compile` 的值只能是 `"yes"` 或者 `"no"`, 53 | 54 | ```julia 55 | function from_toml(compile, threads, optimize, startup) 56 | compile in ("yes", "no") || error("expect yes or no for compile") 57 | JuliaOptions(compile, threads, optimize, startup) 58 | end 59 | ``` 60 | 61 | 并且我们需要实现一个关键字函数来支持有默认参数的项。 62 | 63 | ```julia 64 | function from_toml(;compile="yes", threads=2, optimize=3, startup="no") 65 | compile in ("yes", "no") || error("expect yes or no for compile") 66 | JuliaOptions(compile, threads, optimize, startup) 67 | end 68 | ``` 69 | 70 | 71 | 72 | --- 73 | layout: two-cols 74 | --- 75 | 76 | 更进一步,由于我们的工程有大量的配置信息,并且有一些工程 77 | 会**共享相同的配置信息**,我们需要定义有更加复杂结构的 78 | 配置文件,并且让不同的模块能够**互相组合** 79 | 80 | ```julia 81 | struct LargeOptions 82 | # ... 83 | julia::JuliaOptions 84 | # ... 85 | end 86 | ``` 87 | 88 | ::right:: 89 | 90 | 91 | 92 | 现在以上步骤以及更多的功能只需要 93 | 94 | ```julia 95 | using Configurations 96 | @option struct JuliaOptions 97 | compile::String = "yes" 98 | threads::Int = 1 99 | optimize::Int = 3 100 | startup::String = "no" 101 | end 102 | 103 | @option struct LargeOptions 104 | # ... 105 | julia::JuliaOptions 106 | # ... 107 | end 108 | ``` 109 | 110 | 即可解锁 111 | 112 | 113 | 114 | --- 115 | layout: two-cols 116 | --- 117 | 118 | ## 利用类型转换来验证数据模式 119 | 120 | 由于Julia有强类型,我们可以利用类型来实现对值的验证 121 | 122 | ```julia 123 | julia> @option struct MyOption 124 | a::Int 125 | b::Symbol 126 | end 127 | 128 | 129 | julia> d = Dict{String, Any}( 130 | "a" => 1, 131 | "b" => "ccc" 132 | ) 133 | Dict{String, Any} with 2 entries: 134 | "b" => "ccc" 135 | "a" => 1 136 | ``` 137 | 138 | ::right:: 139 | 140 | 我们可以为特定的参数定义其类型转换 141 | 142 | ```julia 143 | julia> from_dict(MyOption, d) 144 | ERROR: FieldTypeConversionError: conversion from String to type Symbol for field b in type Main.MyOption failed 145 | 146 | julia> function Configurations.from_dict(::Type{MyOption}, ::OptionField{:b}, ::Type{Symbol}, s) 147 | s isa String && s == "ccc" || error("expect ccc") 148 | return Symbol(s) 149 | end 150 | ``` 151 | 152 | --- 153 | layout: two-cols 154 | --- 155 | 156 | ## 可组合的配置类型 157 | 158 | `@option` 在定义相关数据模式解析方法和类型的时候也会定义一系列 159 | 操作接口使得这一系列类型变得可以组合。 160 | 161 | ```julia 162 | "Option A" 163 | @option "option_a" struct OptionA 164 | name::String 165 | int::Int = 1 166 | end 167 | 168 | "Option B" 169 | @option "option_b" struct OptionB 170 | opt::OptionA = OptionA(; name="Sam") 171 | float::Float64 = 0.3 172 | end 173 | 174 | @option struct OptionC 175 | num::Float64 176 | 177 | function OptionC(num::Float64) 178 | num > 0 || error("not positive") 179 | return new(num) 180 | end 181 | end 182 | ``` 183 | 184 | ::right:: 185 | 186 | 187 | 188 | ## 方法一览 189 | 190 | 我们的接口非常之简单,以下是操作一个 `@option` 标记的类型所需要知道的所有方法 191 | 192 | ```julia 193 | @option 194 | field_default 195 | type_alias 196 | is_option 197 | from_dict 198 | from_kwargs 199 | from_toml 200 | from_toml_if_exists 201 | to_dict 202 | ``` 203 | 204 | 他们都有详细的文档说明 205 | 206 | 207 | 208 | 209 | --- 210 | 211 | 一些使用Configurations的工程 212 | 213 | 214 | 215 | | | | 216 | | ----------------- | --------------- | 217 | | TerminalClock | QuantumESPRESSO | 218 | | Workflows | Polymer | 219 | | Bloqade | Workflows | 220 | | PlutoSliderServer | Comonicon | 221 | -------------------------------------------------------------------------------- /pages/expronicon.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: section 3 | --- 4 | 5 | # Expronicon 6 | ## 基于[MLStyle](https://github.com/thautwarm/MLStyle.jl)的元编程工具箱 7 | 8 | --- 9 | layout: section 10 | --- 11 | 12 | # 什么是元编程 13 | ## Meta Programming 14 | 15 | --- 16 | layout: quote 17 | --- 18 | 19 | # “程序即数据” 20 | 21 | 将程序作为数据处理的函数就是元编程里宏(macro) 22 | 23 | --- 24 | layout: two-cols 25 | --- 26 | 27 | ## 需求 28 | 29 | (`Base.@kwdef`) 从以下语法表达式作为输入 30 | 31 | ```julia 32 | struct MyKwType 33 | a::Int = 1 34 | b::Vector{Int} = 2 35 | end 36 | ``` 37 | 38 | 产生 39 | 40 | ```julia 41 | struct MyKwType 42 | a::Int 43 | b::Vector{Int} 44 | end 45 | 46 | function MyKwType(;a::Int = 1, b::Vector{Int} = 2) 47 | MyKwType(a, b) 48 | end 49 | ``` 50 | 51 | ::right:: 52 | 53 | ## 思路 54 | 55 | 56 | 57 | - 扫描表达式,分离结构体表达式和各个元素的赋值表达式 58 | 59 | 60 | 61 | 62 | 63 | - 分析结构体表达式的类型定义信息(类型参数,子类型关系) 64 | 65 | 66 | 67 | 68 | 69 | 70 | - 将结构体表达式复制进新的表达式 71 | 72 | 73 | 74 | 75 | 76 | - 分析结构体表达式,构造关键字构造函数 77 | 78 | 79 | 80 | 81 | 82 | - 将以上产生的表达式按照顺序组合在一起 83 | 84 | 85 | 86 | 87 | --- 88 | layout: section 89 | --- 90 | 91 | # Expronicon的功能概览 92 | 93 | --- 94 | layout: statement 95 | --- 96 | 97 | # 方便的 98 | # 表达式操作 99 | 100 | --- 101 | layout: two-cols 102 | --- 103 | 104 | ## 函数中间格式 105 | 106 | ```julia 107 | julia> JLFunction( 108 | head=:function, 109 | name=:(object::MyObject), 110 | args=[:x, :(y::Int)], 111 | body=quote 112 | x + y 113 | end 114 | ) 115 | function object::MyObject(x, y::Int) 116 | #= REPL[19]:6 =# 117 | x + y 118 | end 119 | ``` 120 | 121 | ::right:: 122 | 123 | ## 结构体中间格式 124 | 125 | ```julia 126 | julia> JLStruct( 127 | name=:MyType, 128 | supertype=:MySuperType, 129 | fields=[ 130 | JLField(name=:x, type=:Int), 131 | JLField(name=:y, type=:T), 132 | ], 133 | doc="a demo type", 134 | ) 135 | """ 136 | a demo type 137 | """ 138 | struct MyType <: MySuperType 139 | x::Int 140 | y::T 141 | end 142 | JLKwStruct 143 | ``` 144 | 145 | --- 146 | layout: two-cols 147 | --- 148 | 149 | ## 条件分支(ifelse)中间格式 150 | 151 | ```julia 152 | julia> jl = JLIfElse(ex); 153 | 154 | 155 | julia> JLIfElse(ex) 156 | if x > 100 157 | x + 1 158 | elseif x > 90 159 | x + 2 160 | elseif x > 80 161 | x + 3 162 | else 163 | error("some error msg") 164 | end 165 | ``` 166 | 167 | ::right:: 168 | 169 | ```julia 170 | julia> jl.otherwise 171 | quote 172 | #= /Users/roger/Code/Julia/Expronicon/test/print/multi.jl:243 =# 173 | error("some error msg") 174 | end 175 | 176 | julia> jl[:(x > 100)] 177 | quote 178 | #= /Users/roger/Code/Julia/Expronicon/test/print/multi.jl:237 =# 179 | x + 1 180 | end 181 | ``` 182 | 183 | --- 184 | layout: section 185 | --- 186 | 187 | # 海量表达式分析工具 188 | 189 | --- 190 | layout: two-cols 191 | --- 192 | 193 | # 常用表达式分析工具 194 | 195 | - 超过20种表达式分析函数 196 | - 详细的文档,几乎每个函数都有对应的用例 197 | - 直观且统一的接口 198 | - 经过实践检验 199 | 200 | ::right:: 201 | 202 | ```julia 203 | compare_expr 204 | is_function 205 | is_kw_function 206 | is_struct 207 | is_tuple 208 | is_splat 209 | is_ifelse 210 | is_for 211 | is_field 212 | is_field_default 213 | is_datatype_expr 214 | is_matrix_expr 215 | split_function 216 | split_function_head 217 | split_struct 218 | split_struct_name 219 | split_ifelse 220 | uninferrable_typevars 221 | has_symbol 222 | is_literal 223 | is_gensym 224 | alias_gensym 225 | has_kwfn_constructor 226 | has_plain_constructor 227 | guess_type 228 | ``` 229 | 230 | --- 231 | layout: two-cols 232 | --- 233 | 234 | ## 解析函数表达式 235 | 236 | ```julia 237 | julia> ex = :(function f(x::T; a=10)::Int where T 238 | return x 239 | end) 240 | :(function (f(x::T; a = 10)::Int) where T 241 | return x 242 | end) 243 | 244 | julia> jl = JLFunction(ex) 245 | function f(x::T; a = 10)::Int where {T} 246 | return x 247 | end 248 | 249 | julia> jl.head, jl.doc, jl.name, jl.rettype, jl.whereparams 250 | (:function, nothing, :f, :Int, Any[:T]) 251 | ``` 252 | 253 | ::right:: 254 | 255 | ## 解析结构类型定义表达式 256 | 257 | ```julia 258 | julia> ex = :(struct Foo1{N, T} 259 | x::T = 1 260 | end) 261 | :(struct Foo1{N, T} 262 | x::T = 1 263 | end) 264 | 265 | julia> JLKwStruct(ex) 266 | begin 267 | struct Foo1{N, T} 268 | x::T 269 | end 270 | begin 271 | function Foo1{N, T}(; x = 1) where {N, T} 272 | Foo1{N, T}(x) 273 | end 274 | function Foo1{N}(; x = 1) where {N} 275 | Foo1{N}(x) 276 | end 277 | end 278 | nothing 279 | end 280 | ``` 281 | 282 | --- 283 | layout: two-cols 284 | --- 285 | 286 | ## Julia表达式反射 287 | 288 | ```julia 289 | julia> @expr if x > 100 290 | x + 1 291 | elseif x > 90 292 | x + 2 293 | elseif x > 80 294 | x + 3 295 | else 296 | error("some error msg") 297 | end 298 | :(if x > 100 299 | #= REPL[1]:2 =# 300 | x + 1 301 | elseif #= REPL[1]:3 =# x > 90 302 | #= REPL[1]:4 =# 303 | x + 2 304 | elseif #= REPL[1]:5 =# x > 80 305 | #= REPL[1]:6 =# 306 | x + 3 307 | else 308 | #= REPL[1]:8 =# 309 | error("some error msg") 310 | end) 311 | ``` 312 | 313 | 314 | ::right:: 315 | 316 | ## 中间格式反射 317 | 318 | ```julia 319 | julia> def = @expr JLKwStruct struct Foo1{N, T} 320 | x::T = 1 321 | end 322 | begin 323 | struct Foo1{N, T} 324 | x::T 325 | end 326 | begin 327 | function Foo1{N, T}(; x = 1) where {N, T} 328 | Foo1{N, T}(x) 329 | end 330 | function Foo1{N}(; x = 1) where {N} 331 | Foo1{N}(x) 332 | end 333 | end 334 | nothing 335 | end 336 | ``` 337 | 338 | --- 339 | layout: two-cols 340 | --- 341 | 342 | # 常用表达式构造工具 343 | 344 | 构造对应表达式的`x`函数,帮助减少 345 | 表达式构造时容易出现的常见错误 346 | 347 | ```julia 348 | xtuple(1, :x) 349 | # :((1, x)) 350 | xnamedtuple(;x=2, y=3) 351 | # :((x = 2, y = 3)) 352 | xcall(Base, :sin, 1; x=2) 353 | # :($Base.sin(1; x = 2)) 354 | xpush(:coll, :x) 355 | # :($Base.push!(coll, x)) 356 | xfirst(:coll) 357 | # :($Base.first(coll)) 358 | xlast(:coll) 359 | # :($Base.last(coll)) 360 | xprint(:coll) 361 | # :($Base.print(coll)) 362 | ``` 363 | 364 | 等20种构造工具 365 | 366 | ::right:: 367 | 368 | # 方便的构造器 369 | 370 | ```julia {all|3|4|6|7|15-22|all} 371 | julia> using Expronicon 372 | 373 | julia> jl = JLIfElse() 374 | nothing 375 | 376 | julia> jl[:(foo(x))] = :(x = 1 + 1) 377 | :(x = 1 + 1) 378 | 379 | julia> jl[:(goo(x))] = :(y = 1 + 2) 380 | :(y = 1 + 2) 381 | 382 | julia> jl.otherwise = :(error("abc")) 383 | :(error("abc")) 384 | 385 | julia> jl 386 | if foo(x) 387 | x = 1 + 1 388 | elseif goo(x) 389 | y = 1 + 2 390 | else 391 | error("abc") 392 | end 393 | ``` 394 | 395 | --- 396 | layout: two-cols 397 | --- 398 | 399 | ## 测试表达式并不方便 400 | 401 | ```julia 402 | julia> lhs = Expr(:block, :(1 + 1)) 403 | quote 404 | 1 + 1 405 | end 406 | 407 | julia> rhs = quote 1 + 1 end 408 | quote 409 | #= REPL[15]:1 =# 410 | 1 + 1 411 | end 412 | 413 | julia> lhs == rhs 414 | false 415 | ``` 416 | 417 | ::right:: 418 | 419 | 420 | 421 | ## 表达式测试工具 422 | 423 | 大部分时候我们只关心 **语义** 上表达式是否相等 424 | 425 | ```julia 426 | julia> using Test 427 | 428 | julia> @test_expr lhs == rhs 429 | Test Passed 430 | ``` 431 | 432 | 433 | 434 | 435 | 436 | `@test_expr` 忽略不影响语义的表达式,然后进行比较, 437 | 毋需浪费资源对表达式求值就可以进行测试。 438 | 439 | 440 | 441 | --- 442 | layout: two-cols 443 | --- 444 | ## 代数类型 445 | 446 | 直接用Julia实现的代数类型(Algebra Data Type) 447 | 448 | ```julia 449 | struct Call 450 | name 451 | args 452 | end 453 | 454 | struct Plus 455 | lhs 456 | rhs 457 | end 458 | 459 | struct Add 460 | lhs 461 | rhs 462 | end 463 | ``` 464 | 465 | 466 | 467 | 类型不稳定! 468 | 469 | 470 | 471 | ::right:: 472 | 473 | 类型稳定的Rust-like代数类型 474 | 475 | ```julia 476 | @adt Term begin 477 | struct Call 478 | name 479 | args 480 | end 481 | 482 | struct Plus 483 | lhs 484 | rhs 485 | end 486 | 487 | struct Add 488 | lhs 489 | rhs 490 | end 491 | end 492 | ``` 493 | 494 | 495 | 496 | 限制: 无法支持参数类型(参数类型会类型不稳定) 497 | 498 | 499 | 500 | --- 501 | 502 | ## 总结 503 | 504 | - 方便操作的表达式中间格式 505 | - 常用表达式分析工具 506 | - 常用表达式构造工具 507 | - 表达式测试工具 508 | 509 | 510 | 511 | 实战检验: Configurations, Comonicon 512 | 513 | 514 | -------------------------------------------------------------------------------- /slides.old.md: -------------------------------------------------------------------------------- 1 | --- 2 | # try also 'default' to start simple 3 | theme: seriph 4 | # random image from a curated Unsplash collection by Anthony 5 | # like them? see https://unsplash.com/collections/94734566/slidev 6 | background: https://source.unsplash.com/collection/94734566/1920x1080 7 | # apply any windi css classes to the current slide 8 | class: 'text-center' 9 | # https://sli.dev/custom/highlighters.html 10 | highlighter: shiki 11 | # show line numbers in code blocks 12 | lineNumbers: false 13 | # some information about the slides, markdown enabled 14 | info: | 15 | ## Slidev Starter Template 16 | Presentation slides for developers. 17 | 18 | Learn more at [Sli.dev](https://sli.dev) 19 | # persist drawings in exports and build 20 | drawings: 21 | persist: false 22 | # use UnoCSS 23 | css: unocss 24 | --- 25 | 26 | # Welcome to Slidev 27 | 28 | Presentation slides for developers 29 | 30 |
31 | 32 | Press Space for next page 33 | 34 |
35 | 36 |
37 | 40 | 42 | 43 | 44 |
45 | 46 | 49 | 50 | --- 51 | 52 | # What is Slidev? 53 | 54 | Slidev is a slides maker and presenter designed for developers, consist of the following features 55 | 56 | - 📝 **Text-based** - focus on the content with Markdown, and then style them later 57 | - 🎨 **Themable** - theme can be shared and used with npm packages 58 | - 🧑‍💻 **Developer Friendly** - code highlighting, live coding with autocompletion 59 | - 🤹 **Interactive** - embedding Vue components to enhance your expressions 60 | - 🎥 **Recording** - built-in recording and camera view 61 | - 📤 **Portable** - export into PDF, PNGs, or even a hostable SPA 62 | - 🛠 **Hackable** - anything possible on a webpage 63 | 64 |
65 |
66 | 67 | Read more about [Why Slidev?](https://sli.dev/guide/why) 68 | 69 | 73 | 74 | 85 | 86 | 89 | 90 | --- 91 | 92 | # Navigation 93 | 94 | Hover on the bottom-left corner to see the navigation's controls panel, [learn more](https://sli.dev/guide/navigation.html) 95 | 96 | ### Keyboard Shortcuts 97 | 98 | | | | 99 | | --- | --- | 100 | | right / space| next animation or slide | 101 | | left / shiftspace | previous animation or slide | 102 | | up | previous slide | 103 | | down | next slide | 104 | 105 | 106 | 111 |

Here!

112 | 113 | --- 114 | layout: image-right 115 | image: https://source.unsplash.com/collection/94734566/1920x1080 116 | --- 117 | 118 | # Code 119 | 120 | Use code snippets and get the highlighting directly![^1] 121 | 122 | ```ts {all|2|1-6|9|all} 123 | interface User { 124 | id: number 125 | firstName: string 126 | lastName: string 127 | role: string 128 | } 129 | 130 | function updateUser(id: number, update: User) { 131 | const user = getUser(id) 132 | const newUser = { ...user, ...update } 133 | saveUser(id, newUser) 134 | } 135 | ``` 136 | 137 | 138 | 139 | [^1]: [Learn More](https://sli.dev/guide/syntax.html#line-highlighting) 140 | 141 | 152 | 153 | --- 154 | 155 | # Components 156 | 157 |
158 |
159 | 160 | You can use Vue components directly inside your slides. 161 | 162 | We have provided a few built-in components like `` and `` that you can use directly. And adding your custom components is also super easy. 163 | 164 | ```html 165 | 166 | ``` 167 | 168 | 169 | 170 | 171 | Check out [the guides](https://sli.dev/builtin/components.html) for more. 172 | 173 |
174 |
175 | 176 | ```html 177 | 178 | ``` 179 | 180 | 181 | 182 |
183 |
184 | 185 | 194 | 195 | 196 | --- 197 | class: px-20 198 | --- 199 | 200 | # Themes 201 | 202 | Slidev comes with powerful theming support. Themes can provide styles, layouts, components, or even configurations for tools. Switching between themes by just **one edit** in your frontmatter: 203 | 204 |
205 | 206 | ```yaml 207 | --- 208 | theme: default 209 | --- 210 | ``` 211 | 212 | ```yaml 213 | --- 214 | theme: seriph 215 | --- 216 | ``` 217 | 218 | 219 | 220 | 221 | 222 |
223 | 224 | Read more about [How to use a theme](https://sli.dev/themes/use.html) and 225 | check out the [Awesome Themes Gallery](https://sli.dev/themes/gallery.html). 226 | 227 | --- 228 | preload: false 229 | --- 230 | 231 | # Animations 232 | 233 | Animations are powered by [@vueuse/motion](https://motion.vueuse.org/). 234 | 235 | ```html 236 |
240 | Slidev 241 |
242 | ``` 243 | 244 |
245 |
246 | 253 | 260 | 267 |
268 | 269 |
274 | Slidev 275 |
276 |
277 | 278 | 279 | 293 | 294 |
298 | 299 | [Learn More](https://sli.dev/guide/animations.html#motion) 300 | 301 |
302 | 303 | --- 304 | 305 | # LaTeX 306 | 307 | LaTeX is supported out-of-box powered by [KaTeX](https://katex.org/). 308 | 309 |
310 | 311 | Inline $\sqrt{3x-1}+(1+x)^2$ 312 | 313 | Block 314 | $$ 315 | \begin{array}{c} 316 | 317 | \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & 318 | = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ 319 | 320 | \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ 321 | 322 | \nabla \cdot \vec{\mathbf{B}} & = 0 323 | 324 | \end{array} 325 | $$ 326 | 327 |
328 | 329 | [Learn more](https://sli.dev/guide/syntax#latex) 330 | 331 | --- 332 | 333 | # Diagrams 334 | 335 | You can create diagrams / graphs from textual descriptions, directly in your Markdown. 336 | 337 |
338 | 339 | ```mermaid {scale: 0.5} 340 | sequenceDiagram 341 | Alice->John: Hello John, how are you? 342 | Note over Alice,John: A typical interaction 343 | ``` 344 | 345 | ```mermaid {theme: 'neutral', scale: 0.8} 346 | graph TD 347 | B[Text] --> C{Decision} 348 | C -->|One| D[Result 1] 349 | C -->|Two| E[Result 2] 350 | ``` 351 | 352 | ```plantuml {scale: 0.7} 353 | @startuml 354 | 355 | package "Some Group" { 356 | HTTP - [First Component] 357 | [Another Component] 358 | } 359 | 360 | node "Other Groups" { 361 | FTP - [Second Component] 362 | [First Component] --> FTP 363 | } 364 | 365 | cloud { 366 | [Example 1] 367 | } 368 | 369 | 370 | database "MySql" { 371 | folder "This is my folder" { 372 | [Folder 3] 373 | } 374 | frame "Foo" { 375 | [Frame 4] 376 | } 377 | } 378 | 379 | 380 | [Another Component] --> [Example 1] 381 | [Example 1] --> [Folder 3] 382 | [Folder 3] --> [Frame 4] 383 | 384 | @enduml 385 | ``` 386 | 387 |
388 | 389 | [Learn More](https://sli.dev/guide/syntax.html#diagrams) 390 | 391 | --- 392 | src: ./pages/multiple-entries.md 393 | hide: false 394 | --- 395 | 396 | --- 397 | layout: center 398 | class: text-center 399 | --- 400 | 401 | # Learn More 402 | 403 | [Documentations](https://sli.dev) · [GitHub](https://github.com/slidevjs/slidev) · [Showcases](https://sli.dev/showcases.html) 404 | --------------------------------------------------------------------------------