slot deposit pulsa slot mahjong slot gacor slot gacor slot gacor resmi slot gacor 2025 slot gacor terpercaya slot gacor 2025 slot gacor hari ini slot gacor hari ini slot gacor hari ini
新型函数式编程语言 Gleam
17611538698
webmaster@21cto.com

新型函数式编程语言 Gleam

编程语言 0 1006 2024-06-28 07:33:05

Gleam 是一种类型安全的函数式编程语言,用于构建可扩展的并发系统。它是否如其宣传的那样友好?我们来一探究竟。

图片

当我的一位朋友读到Virgil 的文章(Wasm 联合创始人介绍新编程语言 Virgil)时,他建议我看看Gleam 。

Gleam 语言很酷也很新,其版本 1.0 在今年 3 月正式发布,并且它在函数式编程方面表现突出。

Gleam 是一种类型安全的函数式编程语言,用于构建可扩展的并发系统。

它可编译为Erlang和JavaScript,因此可与其他“BEAM”语言(如 Erlang 和 Elixir)直接互操作。(BEAM 是在 Erlang 运行时系统中执行用户代码的虚拟机,它是Bogdan 的 Erlang 抽象机的缩写)

Erlang 是一种早期的电信行业语言,非常注重并发性和容错性。它的做事方式至今仍受到尊重,这也是Elixir如此受欢迎的原因。在这篇文章中,我不会假设您熟悉这些;实际上,Gleam 特别友好,因此它也不会做太多假设。

让我们从hello world开始:

import gleam/io
pub fn main() {
io.println("hello world!")
}


这与Zig 中的相同内容非常相似。

有一个非常令人愉快的语言之旅,它利用 Gleam 的编译为 JavaScript 来进行动态检查。您也可以把它用作“游乐场”。

安装 Gleam也意味着要安装 Erlang。对于我的 Mac,使用了 Homebrew:

> brew install gleam

Homebrew 将自动安装 Erlang。

Gleam 带有模板(或项目)生成器,这点与 Rails 非常相似。因此要创建一个新的hello项目,只需输入如下:

图片

“hello world”风格的单行代码已经作为默认代码存在于hello.gleam中:

图片

此时,如果我运行整个项目:

图片

请您注意,这两个包仅在第一次运行时进行编译。

包管理

有两个.toml文件(Tom 自己的标记语言),用作配置。

由于它们很简单,我们可以快速浏览一下。在gleam.toml 中:

[dependencies]
gleam_stdlib = ">= 0.34.0 and < 2.0.0"


请注意,它们有一个版本限制——提及最高版本以减少不兼容性。

manifest.toml 文件中提到了实际下载和当前使用的版本。

下面是一个简单的示例,我们可以学习一点 Gleam 并使用包管理器。我们将添加几个包,并编写一些代码来打印出环境变量。我将使用相同的hello项目模板,但插入了新代码。

首先,我们将添加新的软件包以允许读取环境(envoy)和读取命令行参数(argv)——您可能希望它是内置的,但可能会反映系统差异。

图片

让我们将hello.gleam中的代码替换为按需打印出环境变量,代码如下:

import argv
import envoy
import gleam/io
import gleam/result
pub fn main() {
case argv.load().arguments {
["get", name] -> get(name)
_ -> io.println("Usage: get ")
}
}
fn get(name: String) -> Nil {
let value = envoy.get(name) |> result.unwrap("")
io.println(format_pair(name, value))
}
fn format_pair(name: String, value: String) -> String {
name <> "=" <> value
}


添加到公共main入口点后,我们有两个函数。它们使用的格式与在 Virgil 中看到的完全相同。

事实证明,类型注释是可选的,但被认为是良好做法。现在,我们有点功能性了。argv load执行了您期望的操作,并提取了一个希望恰好包含两个字符串的列表 — 其中第一个字符串等于“get”。这在语句中使用case。

顺便说一下,Gleamcase比大多数非函数式语言更灵活一些。下面我们来比较一下列表的内容:

let result = case x {
[] -> "Empty list"
[1] -> "List of just 1"
[4, ..] -> "List starting with 4"
[_, _] -> "List of 2 elements"
_ -> "Some other list"
}

因此,可以在 case 语句中比较模式。下划线_表示默认,并且会详尽检查可能的情况。

回到我们的环境变量读取代码,如果模式不是两个字符串的列表,则输出帮助文本。否则,它将调用get函数。

我们看到了管道函数,它有助于使长函数调用从左到右更易读。

let value = envoy.get(name) |> result.unwrap("")

这与以下内容相同:

let value = result.unwrap(envoy.get(name),"")

由于 Gleam 不会引发异常,因此它使用内置的Result类型,并解包获取好的路径值。

最后的奇怪之处是:

name <> "=" <> value

这只是字符串连接。

在这里,我第二次运行它,并使用所需的参数:

图片

Gleam 没有 null,没有隐式转换,也没有异常。所以如果它编译成功,那就没问题了。此外,没有数值运算符重载,因此用于添加整数的代码与用于添加浮点数的代码不同:

io.debug(1 + 1) //intsio.debug(1.0 +. 1.5) //floats

相等性适用于任何类型。通过使用函数式语言可以最好地体验不变性的一般概念,因此我不会对此进行掩盖。它确实有助于消除一大堆错误。

代数数据类型

最后,我们看到了Virgil中使用的代数数据类型(ADT) ,所以我很想看看 Gleam 中与之等效的工作原理。事实上,我们已经看到了case语句的用法。

我们获得自定义类型,然后对其进行模式匹配:

pub type Season {  Spring  Summer  Autumn    Winter}

fn weather(season: Season) -> String { case season { Spring -> "Mild" Summer -> "Hot" Autumn -> "Windy" Winter -> "Cold" }}

类型可以在记录中保存数据,这就是我们接近 Virgil 示例的方式:

import gleam/io
pub type Travel { Walk(hours: Int) Cycle(hours: Int) Drive(hours: Int, speed: Int)}

pub fn main() { let walking = Walk(1) let cycling = Cycle(1) let bus_trip = Drive(2, 50)

let trip = [walking, cycling, bus_trip] io.debug(trip)}



// [Walk(hours: 1), Cycle(hours: 1), Drive(hours: 2, speed: 50)]

我认为我无法在类型内关联方法,但我可以访问记录值以获得与 Virgil 中类似的结果。我将把这留给更熟练的用户作为练习!

对于像我这样不怎么使用函数式代码的人来说,Gleam 非常容易上手,不会让我立即陷入“柯里化”等术语和其他函数式冲击中。

但如果您还不是 Gleam 的拥护者,那么 Gleam 应该是一种让您领略编程不变性优势的好方法。

作者:福星

评论