"
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 |
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 |
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 |
--------------------------------------------------------------------------------