使用ReasonML变得合理-第1部分

RTOP,数据类型,Let绑定,词法作用域,If-Else和Switch,记录和变体

ReasonML (简称Reason)不仅是一种新语言,还是一种由OCaml支持的语法和工具链。 它为OCaml提供了一种熟悉的语法,适用于JavaScript程序员,还可以满足NPM / Yarn工作流程的需要。

借助BuckleScript ,Reason可以编译为可读的JavaScript代码。 也可以将其编译为快速的裸机组件。

原因是静态类型的,这在改进代码库的同时为我们提供了更好的清晰度。 编译器本身可以推断大多数类型,而不是一直写所有类型。

这是3部分系列的 第1 部分 ,在这里我将帮助您理解ReasonML及其所有语法和语义。 我将介绍从基本数据类型到在ReasonML中声明函数的所有内容。

设置和RTOP

原因CLI

在开始之前,请确保已在系统上安装了最新版本的Reason CLI

如果您使用的是macOS,请打开终端并输入此命令。

npm install -g reason-cli@3.1.0-darwin

这将在您的系统上安装Reason CLI,以及Reformat和Merlin。 您还将获得RTOP,这是一个交互式命令行工具。 该工具将使我们的工作变得非常简单。

使用RTOP

如果在命令终端中键入rtop ,则将如下所示:

如果您输入一些基本数学运算,例如1 + 1; ,RTOP将对其进行评估并获得结果。

Reason # 1 + 1;
- : int = 2

RTOP的输出由三部分组成。

let binding: type definition = result

如果您没有在1 + 1之后输入分号,则RTOP不会触发评估。

您可能已经注意到终端底部有列表。 该列表将为我们提供一组可能使用的模块和功能。

当我们print出值时,我们将看到值和评估结果。

Reason # print_int(42);
42- : unit = ()

数据类型和运算符

浮点数

如果尝试使用RTOP进行1.1 + 2.2操作,则会收到一条错误消息,因为Reason具有用于处理浮点值的特殊运算符。

为了执行浮点值的运算,我们需要添加一个. 在操作员旁边。 因此1.1 + 2.2将变为:

Reason # 1.1 +. 2.2
- : float = 3.30000000000000027
比较值

为了比较值,我们可以使用几个关系运算符,或者使用==结构相等。

Reason # 2 > 3;
- : bool = false
Reason # 2 == 3;
- : bool = false

您不能直接将int值与float值进行比较。 为此,我们需要先将int转换为float。

Reason # float_of_int(2) > 3.1;
- : bool = false

Reason带有许多此类实用程序功能,可以帮助我们转换类型。

Reason # bool_of_string(“true”);
- : bool = true;
布尔型

由于布尔值只能为true或false,因此Reason与我们通常在JavaScript中所做的没有太大区别。 布尔运算符是! 对于NOT&&对于AND ,和|| 对于OR

弦乐

字符串也很简单。 它们仅受"" 。 字符串可以使用++连接。

Reason # "Hello" ++ "World"
- : string = "HelloWorld"

原因还带有用于单字母字符串的特殊数据类型。

Reason # 'a';
- : char = 'a';
空值

在Reason中传递null值与我们在JavaScript中的操作类似。 Null由()定义,并具有自己的类型,称为unit。

Reason # ();
- : unit = ()

让绑定,类型推断和类型别名

让绑定

让绑定使我们能够将值绑定到名称,这与其他语言中的变量声明非常相似。

使用let ,我们可以将字符串值绑定到这样的变量:

Reason # let name: string = "Rajat";
let name: string = "Rajat";

let绑定的一般模式如下所示:

Reason # let <name>: <type> = <expression>;

如果您来自JavaScript背景,那么您可能想知道为什么我们需要提供type 。 这是因为Reason是静态类型的,这与JavaScript等动态类型的语言完全不同。 静态类型语言要求我们在编译时声明或推断类型。

类型推断

我们已经看到了如何声明我们的类型。 现在让我们看一下如何推断它们。

Reason # let rajat = "Rajat";
let rajat: string = "Rajat";

Reason编译器推断值的类型是字符串。 这是一个了不起的功能,因为它使我们无需完全声明类型即可拥有完整的类型安全性。 这意味着类型在Reason中是可选的,但您也可以根据需要显式地写下它们。

不变性

let绑定是不可变的。 因此,如果我们将值绑定到变量,则以后将无法更改它。

但是,我们可以创建一个具有相同名称的新let绑定。 这个新的绑定将覆盖先前的绑定,并且该绑定现在将引用新分配的值。

类型别名

遮蔽了let绑定之后,它与上一个绑定无关。 因此,我们甚至可以为新绑定使用其他类型。

Reason # type score = int;
type score = int;
Reason # let x: score = 10;
let x: score = 10;

词汇范围

原因具有词法范围。 这将设置变量的范围(功能范围),以便只能从定义该变量的代码块中对其进行引用。 像这样声明的变量有时称为私有变量。

首先,我将使用RTOP在Reason中创建一个本地作用域。

Reason # { 100; };
- : int = 100

范围可以包含多个命令式语句。 最后一条语句将自动返回。

Reason # 
{ print_endline("Rajat"); 100; };
Rajat
- : int = 100

在范围内,我们可以访问当前范围之外的绑定。 但let定义的范围内规定不能从外部访问绑定。

Reason # 100;
- : int = 100
Reason # let x = 10;
let x: int = 10;
Reason # {100 + x; };
- : int = 110
Reason #
{
let y = 1;
110 + y;
};
- : int = 111

我们还可以在一个范围内屏蔽一个let绑定,即使使用不同的类型,它也不会影响该本地范围之外的let绑定。

Reason # let rajat = "Rajat";
let rajat: string = "Rajat";
Reason #
{
let rajat = 100;
rajat;
};
- : int = 2
Reason # rajat;
- : string = "Rajat"

If-Else和Switch

如果别的

if-else允许我们根据提供的条件执行不同的表达式。

Reason # let isHungry = true;
let isHungry: bool = true;
Reason # if (isHungry) {"Pizza!"} else {"Still Pizza!"};
- : string = "Pizza"

这里, if是一个表达式,因此可以简化为一个值。 这意味着它可以绑定到let绑定。 在JavaScript之类的语言中, if是一个语句,而不是一个表达式。 尝试将其绑定到名称将引发语法错误。

if是Reason中的一个表达式,这一事实可能非常有用。 但这也有其局限性。 if-else每个分支if-else需要评估为相同的类型,因此我们无法执行以下操作:

Reason # let food = if (isHungry) {"Pizza"};
Error: This expression has type string but an expression was expected of type unit

因此,只要最后一个语句返回类型单位,我们仍然可以将if用于诸如打印值之类的事情。 print_endline这样做。

Reason # if (isHungry) {print_endline("isHungry is set to true")};
isHungry is set to true
- : int = ()
开关

Switch接受一个值并将其与pattern匹配。 然后评估匹配的情况(必须是表达式)。 pattern以其最简单的形式匹配结构相等。

Reason # let lamp =
switch (1) {
| 0 => "off"
| 1 => "on"
| _ => "off"
};
let lamp: string = "on";
Reason # lamp;
- : string = "on"

如果您没有为_添加switch语句,那么Reason将继续向您发送警告,警告情况2 ,然后3 ,依此类推。 _类似于JavaScript中切换的default情况。

模式匹配可以使用任何类型的数据进行。 对于字符串:

switch ("Evie") {
| "Altair" => "One"
| "Ezio" => "Two"
| "Connor" => "Three"
| "Edward" => "Black Flag"
| "Arno" => "Unity"
| "Jacob" => "Syndicate"
| _ => "Unknown"
};
_ : string = "Unknown"

记录

记录使我们可以将各种类型的数据存储到一个结构中,并按名称进行引用。

要创建记录,我们首先必须定义其结构。

type super = {
hero: string,
alias: string,
};

定义后,我们可以为超级英雄创建记录,如下所示:

{ hero: "Superman", alias: "Clark Kent" };
- : super = {hero: "Superman", alias: "Clark Kent"}

默认情况下会推断类型,我们不需要指定它。 我们还可以像这样访问记录的特定字段:

# let super = { hero: "Superman", alias: "Clark Kent"};
let super: super = {hero: "Superman", alias: "Clark Kent"};
# super.hero;
- : string = "Superman"

如果您尝试访问记录中不存在的字段,Reason会向您抛出错误。

另外,您可以将结构与let绑定结合使用。 我们从一个let绑定开始,然后描述如何映射字段,以及放置要结构化的记录。

# let {hero: heroName, alias: aliasName} = super;
let heroName: string = "Superman";
let aliasName: string = "Clark Kent";

我们还可以重组记录的特定字段。

# let {hero: heroName} = super;
let heroName: string = "Superman";

变体

变体允许我们表达数据结构专有的模块选项。

# type answer = Yes | No | Maybe;

这是引用一组标签的变体。 请注意,变体中的标签需要大写。

我们使用let来绑定这些标签:

# let isItRaining: Yes;
let isItRaining: answer = Yes;

使用变体,我们可以表达任意数量的选项。 变体对于switch表达式最有用。 它使我们能够检查变体的所有可能情况。

# let message = 
switch(isItRaining) {
| Yes => "Better take an umbrella"
| No => "Ok then"
| Maybe => "So take an umbrella to be safe"
};
let message: string = "Better take an umbrella";

使用if-else表达式可以实现相同的目的。 但是通过使用带有开关的变体,可以为我们提供大量的类型系统助手。 例如,如果我们忘记覆盖一个情况,编译器将给我们一个类型错误。

变体的每个标签都可以容纳额外的数据。 假设您要创建一个既可以用作记事又可以用作待办事项的应用程序。 注意将仅期望字符串输入,而待办事项则需要字符串以及布尔输入以指示任务是否完成。

# type item = Note(string) | Todo(string, bool);
# let myItem = Todo("write article", false);

我们可以使用解构来做到这一点。 这样,我们可以给出参数的名称,并在箭头后分别使用它们。

# switch (myItem) {
| Note(text) => text
| Todo(text, checked) => text ++ " is done: " ++ string_of_bool(checked)
};
- : string = "write article: false"

我们可以给他们起名字,我们不一定要。 我们还可以将其与标签的确切值进行匹配。

我们可以添加一个与重新设计的网站完全匹配的模式,并将boolean设置为false

# switch(myItem) {
| Note(text) => text
| Todo("redesign website", false) => "Please first fix the app"
| Todo(text, checked) => text ++ " is done: " ++ string_of_bool(checked)
};

未完待续…

到此结束本系列 3 部分的第1部分 。 对于第2部分,请单击此处:

我是Rajat S. Aspiring Coder,任重道远。 热爱漫威电影的死硬DC漫画迷。 以多任务处理而闻名。

感谢您的阅读,希望对您有所帮助! 如果您喜欢此帖子,请and,然后在此处和/或在Twitter上关注我,以随时了解我的新帖子!

From: https://hackernoon.com/get-reason-able-with-reasonml-part-1-ac950188141b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值