探索编程语言:Ocaml

软文推广2周前更新 刘老三
11 0

让我们继续对编程语言的探索,有一种大家都知道的编程语言,用的人不多,但是确实很强大。

OCaml 于 1996 年首次发布,已经存在 28 年了。

有趣的是,OCaml 源自于 1985 年首次发布的 Caml。

OCaml 是一种小众编程语言,这意味着在某些环境中使用非常广泛,但不是主流语言。 Jane Street 的一切都使用 OCaml,使用 OCaml 的著名公司有 Facebook、微软和 Docker。

我第一次学习 OCaml 是在 2015 年左右。我已经了解了 Erlang 和 Haskell,所以下一步是 OCaml,顺便说一句,它是命令式的、面向对象的和函数式的。

我们将使用 Jane Street 的核心库,因此您可能需要安装它:

$ opam install core

好的,让我们进入我们的主题,即创建 LED 数字应用程序。

应用程序应该像这样工作,我们输入1977,它返回:

探索编程语言:Ocaml

现在,请记住,我们希望向 OCaml 新手展示这一点,而不是向经验丰富的开发人员展示。

我们要做的第一件事是创建一个 Map(类似于其他语言中的哈希或字典),以保存 LED 数字的所有组成部分:

let leds = [
(‘0’, [” _ “; “| | “; “|_| “]);
(‘1’, [” “; “| “; “| “]);
(‘2’, [” _ “; ” _| “; “|_ “]);
(‘3’, [“_ “; “_| “; “_| “]);
(‘4’, [” “; “|_| “; ” | “]);
(‘5’, [” _ “; “|_ “; ” _| “]);
(‘6’, [” _ “; “|_ “; “|_| “]);
(‘7’, [“_ “; ” | “; ” | “]);
(‘8’, [” _ “; “|_| “; “|_| “]);
(‘9’, [” _ “; “|_| “; ” _| “])

我们将每个数字分成三行。例如,如果我们要打印数字6,我们可以这样做:

open Core

let get_leds =
let leds = [
(‘0’, [” _ “; “| | “; “|_| “]);
(‘1’, [” “; “| “; “| “]);
(‘2’, [” _ “; ” _| “; “|_ “]);
(‘3’, [“_ “; “_| “; “_| “]);
(‘4’, [” “; “|_| “; ” | “]);
(‘5’, [” _ “; “|_ “; ” _| “]);
(‘6’, [” _ “; “|_ “; “|_| “]);
(‘7’, [“_ “; ” | “; ” | “]);
(‘8’, [” _ “; “|_| “; “|_| “]);
(‘9’, [” _ “; “|_| “; ” _| “])
] in
let line = List.Assoc.find_exn ~equal:Char.equal leds ‘6’ in
printf ” %s \n %s \n %s” (List.nth_exn line 0) (List.nth_exn line 1) (List.nth_exn line 2)

let () =
get_leds

看起来很多吧?好吧,在 Ocaml 中你需要维护一定的结构,所以让我们花点时间来分析一下:

  • 我们称之为核心模块。
  • 我们正在定义名为get_leds的主函数。
  • 在我们的函数中,我们正在定义LED地图。
  • 我们将在名为line的变量的定义中使用leds映射变量。该变量将读取地图并获取与ƌ’关联的值。List.Assoc.find_exn允许我们从映射中检索值。~equal:Char.equal允许我们使用字符来查找值。
  • 一旦我们有了值,我们就想打印每一行。
  • 最后,我们调用我们的 main 函数。

结果是:

_
|_
|_|

当然,我们想打印多个数字,因此我们的想法是将每个数字的行连接起来,然后打印它们:

open Core

let get_leds =
let leds = [
(‘0’, [” _ “; “| | “; “|_| “]);
(‘1’, [” “; “| “; “| “]);
(‘2’, [” _ “; ” _| “; “|_ “]);
(‘3’, [“_ “; “_| “; “_| “]);
(‘4’, [” “; “|_| “; ” | “]);
(‘5’, [” _ “; “|_ “; ” _| “]);
(‘6’, [” _ “; “|_ “; “|_| “]);
(‘7’, [“_ “; ” | “; ” | “]);
(‘8’, [” _ “; “|_| “; “|_| “]);
(‘9’, [” _ “; “|_| “; ” _| “])
] in
let line = List.Assoc.find_exn ~equal:Char.equal leds ‘6’ in
let line2 = List.Assoc.find_exn ~equal:Char.equal leds ‘2’ in
printf ” %s%s \n %s%s \n %s%s”
(List.nth_exn line 0) (List.nth_exn line2 0)
(List.nth_exn line 1) (List.nth_exn line2 1)
(List.nth_exn line 2) (List.nth_exn line2 2)

let () =
get_leds

结果是这样的:

_ _
|_ _|
|_| |_

当然,我们需要一种方法来自动执行此操作,因为数字越长,我们的打印命令就越长,而且我们不希望有任何硬编码。

好的,我们有 3 行需要打印。但却是一个未知的数字。在运行时了解我们的号码有多少位非常重要,以便我们采取相应的行动。假设我们要打印数字1593,所以我们有4 位数字,我们需要打印 3 行,每行包含这 4 位数字的部分,所以这是我们的应用程序代码:

open Core

let get_leds number =
let leds = [
(‘0’, [” _ “; “| | “; “|_| “]);
(‘1’, [” “; “| “; “| “]);
(‘2’, [” _ “; ” _| “; “|_ “]);
(‘3’, [“_ “; “_| “; “_| “]);
(‘4’, [” “; “|_| “; ” | “]);
(‘5’, [” _ “; “|_ “; ” _| “]);
(‘6’, [” _ “; “|_ “; “|_| “]);
(‘7’, [“_ “; ” | “; ” | “]);
(‘8’, [” _ “; “|_| “; “|_| “]);
(‘9’, [” _ “; “|_| “; ” _| “])
] in
for i = 0 to 2 do
for j = 0 to String.length number – 1 do
let line = List.Assoc.find_exn ~equal:Char.equal leds number.[j] in
printf “%s” (List.nth_exn line i)
done;
print_string “\n”
done

let () =
print_string “Enter a number: “;
Out_channel.flush stdout;
let num = In_channel.input_line_exn stdin in
get_leds num

在这里,我们使用 print_string 请求一个数字,并调用Out_channel.flush stout以确保它打印在终端上。我们定义一个名为 num 的变量,它将保存用户使用In_channel.input_line_exn stdin键入的输入。我们希望在get_leds函数中使用该信息。

在get_leds内部,我们将使用for关键字执行循环操作。外循环将循环 3 次,而内循环将循环输入的位数。

我们不会在变量中存储任何值,而是直接在终端上打印结果。printf允许我们继续打印,除非有明确的print_string \n。对于此示例,我们将打印数字1593。

为了让事情变得更容易,让我们调试我们的应用程序并查看每次迭代中会出现哪些值:

  • 我们输入数字1593 ,并以i的值为0开始外循环。
  • 在内部循环中,j的值为0,并将一直上升到3(因为我们的数字有4位)。
  • 我们将使用let line = List.Assoc.find_exn ~equal:Char.equal leds number.[j]提取数字1593的第一位数字。在 Ocaml 中,字符串只是一个字符列表,因此我们可以轻松地使用number.[j]来获取数字。
  • 我们需要调用printf “%s” (List.nth_exn 第 i 行)来提取需要打印的行部分。这里是0。
_ _ _

我们可以转到第一个循环的第二次迭代。一切都会重复,但例外的是i的值为1,这意味着它将读取第二行。我们将打印以下内容:

_ _ _
| |_ |_| _|

我们最终进入第一个循环的第三次也是最后一次迭代。同样,一切都会重复,但i的值为2,这意味着它将读取第三行。我们将打印以下内容:

_ _ _
| |_ |_| _|
| _| _| _|

然后申请就结束了。如果我们将应用程序命名为LED_Numbers.ml,我们可以在终端窗口上运行它,如下所示:

corebuild LED_Numbers.native

等待?我们的代码扩展名不是.ml吗?是的,但是 corebuild 只需要名称而不需要扩展名。此外,.native将是生成的可执行文件的扩展名。

探索编程语言:Ocaml

OCaml官网 https://ocaml.org/

© 版权声明

相关文章