RTOP,数据类型,Let绑定,词法作用域,If-Else和Switch,记录和变体
![](https://i-blog.csdnimg.cn/blog_migrate/a261e54638a6643469bd8a38496c4667.png)
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
,则将如下所示:
![](https://i-blog.csdnimg.cn/blog_migrate/ce07534132e615e74009eea6772eaba0.png)
如果您输入一些基本数学运算,例如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