6
社区成员
发帖
与我相关
我的任务
分享Julia 可能是迄今为止涵盖的最新语言,于 2015 年发布,旨在取代旧的(通常很糟糕的)科学计算语言。让我们看看它的表现如何。
作为一个有趣的旁注,Jupyter Notebook以 Julia、Python 和 R 命名,尽管在实践中它用于 Python、Python 和 Python。我猜 PyPyPy Notebook 听起来不太对劲。
这里没有什么奇怪的:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-string-color)">"Hello, World!"</span>)
</code></span></span>
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-name-color)"> fib</span>(<span style="color:var(--syntax-text-color)">n</span>)
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">n</span> <span style="color:var(--syntax-error-color)"><=</span> <span style="color:var(--syntax-literal-color)">2</span>
<span style="color:var(--syntax-literal-color)">1</span>
<span style="color:var(--syntax-declaration-color)">else</span>
<span style="color:var(--syntax-text-color)">fib</span>(<span style="color:var(--syntax-text-color)">n</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">1</span>) <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">fib</span>(<span style="color:var(--syntax-text-color)">n</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">2</span>)
<span style="color:var(--syntax-declaration-color)">end</span>
<span style="color:var(--syntax-declaration-color)">end</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">:</span><span style="color:var(--syntax-literal-color)">30</span>
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-text-color)">fib</span>(<span style="color:var(--syntax-text-color)">i</span>))
<span style="color:var(--syntax-declaration-color)">end</span>
</code></span></span>
语法非常接近 Ruby 和 Python。函数不需要 explicit return。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-name-color)"> fizzbuzz</span>(<span style="color:var(--syntax-text-color)">n</span>)
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">n</span> <span style="color:var(--syntax-error-color)">%</span> <span style="color:var(--syntax-literal-color)">15</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span>
<span style="color:var(--syntax-string-color)">"FizzBuzz"</span>
<span style="color:var(--syntax-declaration-color)">elseif</span> <span style="color:var(--syntax-text-color)">n</span> <span style="color:var(--syntax-error-color)">%</span> <span style="color:var(--syntax-literal-color)">5</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span>
<span style="color:var(--syntax-string-color)">"Buzz"</span>
<span style="color:var(--syntax-declaration-color)">elseif</span> <span style="color:var(--syntax-text-color)">n</span> <span style="color:var(--syntax-error-color)">%</span> <span style="color:var(--syntax-literal-color)">3</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span>
<span style="color:var(--syntax-string-color)">"Fizz"</span>
<span style="color:var(--syntax-declaration-color)">else</span>
<span style="color:var(--syntax-text-color)">n</span>
<span style="color:var(--syntax-declaration-color)">end</span>
<span style="color:var(--syntax-declaration-color)">end</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">:</span><span style="color:var(--syntax-literal-color)">100</span>
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-text-color)">fizzbuzz</span>(<span style="color:var(--syntax-text-color)">i</span>))
<span style="color:var(--syntax-declaration-color)">end</span>
</code></span></span>
一切正常,而且非常清晰。是时候做一些更难的事情了。
Julia 内置了对向量和矩阵的支持,所以我们可以用它们做非常快速的斐波那契公式,类似于我们用 Octave 所做的。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">u</span> <span style="color:var(--syntax-error-color)">=</span> [<span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-literal-color)">1</span>]
<span style="color:var(--syntax-text-color)">m</span> <span style="color:var(--syntax-error-color)">=</span> [<span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-literal-color)">1</span>; <span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-literal-color)">0</span>]
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">:</span><span style="color:var(--syntax-literal-color)">40</span>
<span style="color:var(--syntax-text-color)">result</span> <span style="color:var(--syntax-error-color)">=</span> (<span style="color:var(--syntax-text-color)">u</span> <span style="color:var(--syntax-error-color)">*</span> (<span style="color:var(--syntax-text-color)">m</span> <span style="color:var(--syntax-error-color)">^</span> (<span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">1</span>)))[<span style="color:var(--syntax-literal-color)">2</span>]
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-string-color)">"fib(</span><span style="color:var(--syntax-string-color)">$</span><span style="color:var(--syntax-string-color)">i) = </span><span style="color:var(--syntax-string-color)">$</span><span style="color:var(--syntax-string-color)">result"</span>)
<span style="color:var(--syntax-declaration-color)">end</span>
</code></span></span>
这会产生我们所期望的:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ julia fibmatrix.jl
fib(1) = 1
fib(2) = 1
fib(3) = 2
fib(4) = 3
fib(5) = 5
fib(6) = 8
fib(7) = 13
fib(8) = 21
fib(9) = 34
fib(10) = 55
fib(11) = 89
fib(12) = 144
fib(13) = 233
fib(14) = 377
fib(15) = 610
fib(16) = 987
fib(17) = 1597
fib(18) = 2584
fib(19) = 4181
fib(20) = 6765
fib(21) = 10946
fib(22) = 17711
fib(23) = 28657
fib(24) = 46368
fib(25) = 75025
fib(26) = 121393
fib(27) = 196418
fib(28) = 317811
fib(29) = 514229
fib(30) = 832040
fib(31) = 1346269
fib(32) = 2178309
fib(33) = 3524578
fib(34) = 5702887
fib(35) = 9227465
fib(36) = 14930352
fib(37) = 24157817
fib(38) = 39088169
fib(39) = 63245986
fib(40) = 102334155
</code></span></span>
向量和矩阵使用基于 1 的索引,这完全令人畏惧,即使这是计算机时代之前的数学家所习惯的。
"$x"Julia 支持使用变量和"$(...)"表达式进行字符串插值。有点令人失望的是,我们终于来到了一个世界,在这个世界上,每一种智能语言都支持字符串插值,但每一种语言都为其选择了不同的语法。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">strings</span> <span style="color:var(--syntax-error-color)">=</span> [<span style="color:var(--syntax-string-color)">"Hello"</span>, <span style="color:var(--syntax-string-color)">"Żółw"</span>, <span style="color:var(--syntax-string-color)">"🍩"</span>]
<span style="color:var(--syntax-text-color)">println</span>([<span style="color:var(--syntax-text-color)">length</span>(<span style="color:var(--syntax-text-color)">s</span>) <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">s</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-text-color)">strings</span>])
<span style="color:var(--syntax-text-color)">println</span>([<span style="color:var(--syntax-text-color)">uppercase</span>(<span style="color:var(--syntax-text-color)">s</span>) <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">s</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-text-color)">strings</span>])
</code></span></span>
鉴于它是一种新语言,它可以按预期正确处理基本的 Unicode 操作:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ julia unicode.jl
[5, 4, 1]
["HELLO", "ŻÓŁW", "🍩"]
</code></span></span>
还要注意 Python 风格的列表理解。
猜猜它会打印哪个字母:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">s</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">"Żółw"</span>
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-text-color)">s</span>[<span style="color:var(--syntax-literal-color)">3</span>])
</code></span></span>
你猜对了吗?
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ julia unicode2.jl
ó
</code></span></span>
在每一种明智的语言中都是w。即使是 JavaScript 也能做到这一点,但它很少能做到任何事情。
我已经提到 Julia 使用基于 1 的索引,即使是字符串,所以你可能已经猜到了ł,但我们到底是怎么得到的呢w?
事实证明,Julia 从 1 开始按字节位置对字符进行索引。因此对于 string "Żółw",这些是字母:
"Żółw"[1]是'Ż'"Żółw"[3]是'ó'"Żółw"[5]是'ł'"Żółw"[7]是'w'其他所有索引都会引发异常,例如:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>julia> "Żółw"[2]
ERROR: StringIndexError: invalid index [2], valid nearby indices [1]=>'Ż', [3]=>'ó'
</code></span></span>
我们可以调用collect(eachindex("Żółw"))以获取有效索引的列表[1, 3, 5, 7]。
总的来说,我不确定这比 JavaScript 好还是坏。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">println</span>([<span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-literal-color)">2</span>] <span style="color:var(--syntax-error-color)">==</span> [<span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-literal-color)">2</span>])
<span style="color:var(--syntax-text-color)">println</span>([<span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-literal-color)">2</span>; <span style="color:var(--syntax-literal-color)">3</span> <span style="color:var(--syntax-literal-color)">4</span>] <span style="color:var(--syntax-error-color)">==</span> [<span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-literal-color)">2</span>; <span style="color:var(--syntax-literal-color)">3</span> <span style="color:var(--syntax-literal-color)">4</span>])
<span style="color:var(--syntax-text-color)">println</span>((<span style="color:var(--syntax-literal-color)">1</span>,<span style="color:var(--syntax-literal-color)">2</span>) <span style="color:var(--syntax-error-color)">==</span> (<span style="color:var(--syntax-literal-color)">1</span>,<span style="color:var(--syntax-literal-color)">2</span>))
<span style="color:var(--syntax-text-color)">println</span>((<span style="color:var(--syntax-literal-color)">10</span><span style="color:var(--syntax-error-color)">:</span><span style="color:var(--syntax-literal-color)">20</span>) <span style="color:var(--syntax-error-color)">==</span> (<span style="color:var(--syntax-literal-color)">10</span><span style="color:var(--syntax-error-color)">:</span><span style="color:var(--syntax-literal-color)">20</span>))
</code></span></span>
==在所有复杂类型(如向量、矩阵、元组、范围等)上都能正确运行也就不足为奇了:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ julia equality.jl
true
true
true
true
</code></span></span>
Julia 支持许多不同风格的函数式编程:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">numbers</span> <span style="color:var(--syntax-error-color)">=</span> (<span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">:</span><span style="color:var(--syntax-literal-color)">10</span>)
<span style="color:var(--syntax-text-color)">println</span>(
[<span style="color:var(--syntax-text-color)">x</span> <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">x</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-text-color)">numbers</span> <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">x</span> <span style="color:var(--syntax-error-color)">%</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span>]
)
<span style="color:var(--syntax-text-color)">println</span>(
<span style="color:var(--syntax-text-color)">filter</span>(<span style="color:var(--syntax-text-color)">iseven</span>, <span style="color:var(--syntax-text-color)">numbers</span>)
)
<span style="color:var(--syntax-text-color)">println</span>(
<span style="color:var(--syntax-text-color)">filter</span>(<span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">-></span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">%</span><span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span>, <span style="color:var(--syntax-text-color)">numbers</span>)
)
<span style="color:var(--syntax-text-color)">println</span>(
<span style="color:var(--syntax-text-color)">filter</span>(<span style="color:var(--syntax-text-color)">numbers</span>) <span style="color:var(--syntax-declaration-color)">do</span> <span style="color:var(--syntax-text-color)">x</span>
<span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">%</span><span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span>
<span style="color:var(--syntax-declaration-color)">end</span>
)
</code></span></span>
请注意,块参数在语法中排在最后do,但它被转换为函数的第一个参数。
与其他数学程序一样,运算符可以按元素应用于集合。Julia 还提供了方便的语法来将其与您自己的函数一起使用:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">double</span>(<span style="color:var(--syntax-text-color)">x</span>) <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">x</span>
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-text-color)">double</span>(<span style="color:var(--syntax-literal-color)">21</span>))
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-text-color)">double</span><span style="color:var(--syntax-error-color)">.</span>(<span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">:</span><span style="color:var(--syntax-literal-color)">10</span>))
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-literal-color)">10</span> <span style="color:var(--syntax-error-color)">.+</span> [<span style="color:var(--syntax-literal-color)">1</span>,<span style="color:var(--syntax-literal-color)">2</span>,<span style="color:var(--syntax-literal-color)">3</span>])
</code></span></span>
哪些输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ julia dot.jl
42
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[11, 12, 13]
</code></span></span>
.+并且对于适当的类型来说.()是隐式的。map这不是大多数通用语言通常会做的事情,但它在数学代码中更为常见,因此许多数学语言都对此提供了一定程度的支持。
我在 Emojicode 插曲中提到,语言真的会折磨他们的 ASCII 符号,以避免使用 ASCII 之外的任何东西。运算符通常由 2-3 个符号组成,相同的组合通常会被重载以表示很多不同的东西。Julia 采取适度的步骤来使用 Unicode 数学符号。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># is subset</span>
<span style="color:var(--syntax-text-color)">println</span>([<span style="color:var(--syntax-literal-color)">1</span>,<span style="color:var(--syntax-literal-color)">2</span>] <span style="color:var(--syntax-text-color)">⊆</span> [<span style="color:var(--syntax-literal-color)">2</span>,<span style="color:var(--syntax-literal-color)">3</span>,<span style="color:var(--syntax-literal-color)">1</span>])
<span style="color:var(--syntax-comment-color)"># is element</span>
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-literal-color)">3</span> <span style="color:var(--syntax-text-color)">∈</span> [<span style="color:var(--syntax-literal-color)">2</span>,<span style="color:var(--syntax-literal-color)">3</span>,<span style="color:var(--syntax-literal-color)">1</span>])
<span style="color:var(--syntax-comment-color)"># some trigonometry and square roots</span>
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-text-color)">sin</span>(<span style="color:var(--syntax-text-color)">π</span><span style="color:var(--syntax-error-color)">/</span><span style="color:var(--syntax-literal-color)">3</span>) <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-text-color)">√3</span>)
</code></span></span>
哪些输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>true
true
1.4999999999999998
</code></span></span>
Julia 并不过分,我认为未来这种用法会越来越普遍。
对于非 Lisp 用户来说不同寻常的是,Julia 有宏。它们看起来与常规的 Julia 语法不太一样,但确实如此:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">macro</span><span style="color:var(--syntax-name-color)"> unless</span>(<span style="color:var(--syntax-text-color)">condition</span>, <span style="color:var(--syntax-text-color)">expression</span>)
<span style="color:var(--syntax-declaration-color)">quote</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-error-color)">!</span>(<span style="color:var(--syntax-error-color)">$</span><span style="color:var(--syntax-text-color)">condition</span>)
<span style="color:var(--syntax-error-color)">$</span><span style="color:var(--syntax-text-color)">expression</span>
<span style="color:var(--syntax-declaration-color)">end</span>
<span style="color:var(--syntax-declaration-color)">end</span> <span style="color:var(--syntax-error-color)">|></span> <span style="color:var(--syntax-text-color)">esc</span>
<span style="color:var(--syntax-declaration-color)">end</span>
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-string-color)">"Enter number:"</span>)
<span style="color:var(--syntax-text-color)">num</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">parse</span>(<span style="color:var(--syntax-declaration-color)">Int</span>, <span style="color:var(--syntax-text-color)">readline</span>())
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">isodd</span>(<span style="color:var(--syntax-text-color)">num</span>)
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">$</span><span style="color:var(--syntax-string-color)">num is odd"</span>)
<span style="color:var(--syntax-declaration-color)">end</span>
<span style="color:var(--syntax-name-color)">@unless</span> <span style="color:var(--syntax-text-color)">isodd</span>(<span style="color:var(--syntax-text-color)">num</span>) <span style="color:var(--syntax-declaration-color)">begin</span>
<span style="color:var(--syntax-text-color)">println</span>(<span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">$</span><span style="color:var(--syntax-string-color)">num is even"</span>)
<span style="color:var(--syntax-declaration-color)">end</span>
</code></span></span>
哪个按预期工作:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ julia macro.jl
Enter number:
69
69 is odd
$ julia macro.jl
Enter number:
420
420 is even
</code></span></span>
我不知道这在实践中有多重要。许多非 Lisp 语言都尝试过,但这些尝试都没有起到多大作用。一般来说,Julia 对语法非常慷慨。quote...endwith$是 Lisp 术语中的“准引用”。|>只是 Elixir 风格的管道进入另一个函数而不是特定于宏。如果出于某种原因您不想-42 |> abs键入abs(-42).
正如您所看到的,因为 Julia 不是 Lisp,宏引入的语法看起来并不完全相同——还有额外的@东西begin。但也许它对于某些用例来说已经足够好了。
对于 Julia 所针对的任务类型,我通常建议首先尝试使用 Python,但 Julia 并不是一个糟糕的选择。
它是一种相当现代的语言,包袱有限,语法友好,类似于 Python 和 Ruby,您可以使用熟悉的 Jupyter Notebook 开发风格。许多新语言,如 Go、Rust 和 TypeScript,显然是由迷恋遥远过去的精神潮一代创造的,他们拒绝接受现代编程语言设计的许多教训。Julia 不喜欢 - 感觉他们做对了大部分事情,考虑到他们的目标。
大多数其他“数学”语言都有可怕的怪癖、沉重的包袱、糟糕的语法,一旦你走出它们的核心领域就会严重不足,而且通常是专有或半专有的。相比之下,Julia 在所有这些标准上都做得不错。如果他们与 Python 一起结束了一些仍在科学界使用的蹩脚闭源语言的安乐死,那将使世界变得更美好。
我根本没有调查朱莉娅的表现。老实说,我认为整个“性能”的东西真的被高估了,微基准测试完全没有任何现实意义。
总的来说,我认为它非常有前途,即使我可能仍然会首先尝试 Python。