Standard ML快餐教程(1) - 初识

简介: 如何搭建Standard ML开发环境,以及如何在sml中生存下来

Standard ML快餐教程(1) - 初识

好久没写快餐教程了,下面开始一个新的系列,关于函数式编程语言的系列。打算写三种语言:Standard ML,ocaml和Haskell。
这几门语言都不是新贵了,其中Standard ML的知名度可能最低。因为ML系列的影响力,其实我们已经从新的语言如rust等中学到过这些老语言的很多知识了。现在我们可能只要将它们还原回去就好。

运行环境

Standard ML,顾名思义,是ML语言的一种标准规范,主要的版本有SML 90和SML 97。
标准的实现就有很多种方式。比如以交互式编译为主要特点的SML/NJ,还有以优化编译为主要目标的mlton。另外一个重要的Standard ML编译器是剑桥大学的David Matthews开发的poly/ML,因为著名的推理证明工具Isabelle是使用polyml开发的。

SML/NJ是由贝尔实验室的David MacQueen和普林斯顿大学的Andrew Appel于1986年发起的。为了满足1997年SML的修订,1998年1月推出了110版本。时至2020年,主版本号还是110,比如我现在用的版本是v110.97。

SML/NJ的项目主页在:http://www.smlnj.org/。其源代码是使用svn管理的。mlton和polyml的源代码都在github上管理。mlton的地址为:https://github.com/MLton/mlton,ployml的地址为:https://github.com/polyml/polyml/

安装的话,因为以上三种语言工具都属于比较通用成熟的工具,在mac上的homebrew和Ubuntu之类的主流Linux发布版本中都有支持。
比如在macOS上,可以使用homebrew进行安装这三种环境:

brew install mlton
brew install polyml
brew cask install smlnj

在Ubuntu下可以使用下面的命令安装:

apt install smlnj
apt install mlton
apt install polyml

安装好之后,运行sml命令,就可以进入sml/nj的交互式环境,就可以开始学习编写Standard ML代码了,"-"是smlnj的提示符:

Standard ML of New Jersey v110.79 [built: Sat Oct 26 12:27:04 2019]
-

我们可以先写个HelloWorld程序练练手,比如叫hello.sml:

val a = 1 :int ;
print "Hello,World\n";

smlnj可以通过sml hello.sml来调用。
也可以通过mlton hello.sml来编译,然后会生成hello,运行hello就可以看到运行结果。

使用polyc进行编译的时候,会报下面的错误:

poly: : error: Value or constructor (main) has not been declared
Found near PolyML.export (List.nth (CommandLine.arguments (), 3), main)
Static Errors

这是因为polyml需要一个main函数。
我们写个main函数吧:

fun main() = print "Hello,World\n";

然后调用polyc去编译:

polyc hello2.sml -o hello2

最后运行hello2就可以看到运行结果。

polyml也可以通过poly命令交互式运行。

Poly/ML 5.8.1 Release

提示符为">"。

数据类型

我们可以通过交互式界面来了解下基本数据类型的用法。

数字类型

比如我们输入一个整数1:

> 1;
val it = 1: int

我们可以看到,这样一个整数被赋给一个叫it的默认变量,其类型为int.

-1在Standard ML中表示为"~1",我们来看下:

> val a = 0 - 1;
val a = ~1: int

符点数是real类型:

> val b = 1e8;
val b = 100000000.0: real

字符串

Standard ML支持字符串类型:

> val d = "Hello";
val d = "Hello": string

布尔值

Standard ML使用true和false两个关键字来表示bool类型:

> true;
val it = true: bool
> false;
val it = false: bool
> 1>0;
val it = true: bool

空值

Standard ML的空类型为unit,用来表示一个空表():

> ();
val it = (): unit
> val g = ();
val g = (): unit

同样,空的记录也是unit:

> val x3 = {};
val x3 = (): unit

字符类型

通过“#”,也可以描述char类型:

> val e = #"c";
val e = #"c": char

ord函数用来将字符转成整数,chr相反将ASCII值转成字符。

> val x4 = ord(#"a");
val x4 = 97: int
> val x5 = chr(65);
val x5 = #"A": char

数据结构

元组

元组是使用括号描述的列表。类型将成为几个类型之乘积。
比如(3.0, true)的类型是real * bool.

> val x6 = (3.0, true);
val x6 = (3.0, true): real * bool

列表

不同于元组,列表的元素必须是相同的,用方括号表示。
空列表不是unit,也是个列表类型。

- val a1 = [];
val a1 = [] : 'a list

只要类型相同就可以,元组也没问题:

- val a2 = [1,2];
val a2 = [1,2] : int list
- val a3 = ["h","e"];
val a3 = ["h","e"] : string list
- val a4 = [(3,4),(2,5)];
val a4 = [(3,4),(2,5)] : (int * int) list

记录

类似于哈希表的一种结构,指定key与value:

- val a5 = {name="xulun",age=20};
val a5 = {age=20,name="xulun"} : {age:int, name:string}

如果以数字1,2,3等为key,则建立的记录就是元组。我们看个例子:

- val a7 = {1=true, 2=3.0};
val a7 = (true,3.0) : bool * real

多赋值

Standard ML支持模式匹配多赋值,比如我们使用变量元组和值元组,举个例子看下就清楚了:

> val (x1,x2) = (1.0, true);
val x1 = 1.0: real
val x2 = true: bool

语句

函数

可以通过fun来定义函数,我们直接看个求平方的例子:

> fun s2 (x:int):int = x*x;
val s2 = fn: int -> int
> s2(4);
val it = 16: int

可以不指定类型,由系统进行推断:

- fun add1 x y = x + y;
val add1 = fn : int -> int -> int

如果想用浮点类型,可以指定一个,其它由系统推断:

- fun add2 (x:real) y = x + y;
val add2 = fn : real -> real -> real

注释

Standard ML使用(**)来写注释。

条件语句

Standard ML支持if then else语句,如果if为真则返回then后面的表达式,否则返回else分支的结果。

- fun neg1 (x:int) : bool = if x < 0 then true else false;
val neg1 = fn : int -> bool

还记得-1在sml表示为~1吧,我们测试下上面的if判断:

- neg1(1);
val it = false : bool
- neg1(~1);
val it = true : bool

case语句

通过case语句,可以处理多分支的条件,每个条件进行自己的匹配。格式为case x of x1 => something1 | x2 => something2 | ...

我们来看个例子:

- fun grade1(x:int) = case x of 0 => false | 1 => true | x => false;
val grade1 = fn : int -> bool
- grade1(1);
val it = true : bool
- grade1(0);
val it = false : bool
- grade1(100);
val it = false : bool

标准库

做为一种标准语言,Standard ML也支持可移植性的标准库。我们可以调用这些库像其它语言一样愉快地编程了。sml的标准库叫做BASIS。
第一次调用的时候,basis会被加载进来:

- Char.isUpper(#"a");
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
[autoloading done]
val it = false : bool

再来几个例子,比如计算实数的绝对值:

- Real.abs(~1.5);
val it = 1.5 : real

整数转实数:

- val a10 = Real.fromInt(1);
val a10 = 1.0 : real

求平方根:

- val a11 = Math.sqrt(2.0);
[autoloading]
[autoloading done]
val a11 = 1.41421356237 : real

字符串连接:

- val a11 = String.concat(["Hello","World"]);
val a11 = "HelloWorld" : string

一起看起来都不错。类型,分支,函数等都有了。还有强大的标准库,恭喜你,已经在Standard ML的世界里活下来了 :)

目录
相关文章
|
前端开发 测试技术 API
一文掌握软件分支管理
本文详细介绍了软件分支管理的实践经验,结合具体项目案例,从版本号、分支命名、标签管理到合并策略等方面展开。通过清晰的规则和流程图示,帮助团队避免版本混乱,提升研发效率。强调主干与开发分支的核心作用,同时提醒合理控制分支数量,确保协作顺畅。适用于不同类型的项目,助力团队建立适合自身的版本管理体系。
1936 69
一文掌握软件分支管理
|
3月前
|
存储 缓存 关系型数据库
【MySQL】《MySQL索引核心分类面试高频考点问答清单》(附:《一页纸速记版》)
本文系统梳理MySQL索引核心分类与面试高频考点,涵盖B+树原理、聚簇/非聚簇索引区别、联合索引最左前缀、覆盖索引、前缀索引、索引失效场景及ICP/MRR等进阶优化。
|
存储 Linux API
软件体系结构 - 嵌入式系统(2)- 嵌入式操作系统
软件体系结构 - 嵌入式系统(2)- 嵌入式操作系统
680 0
|
8月前
|
负载均衡 应用服务中间件 Nacos
Nacos配置中心
Nacos配置中心通过集中化管理微服务配置,实现动态热更新与环境隔离,避免频繁重启服务。借助bootstrap.yml优先加载配置,支持@RefreshScope热刷新、@ConfigurationProperties绑定,并实现多环境共享及优先级控制,结合Nginx搭建高可用集群,提升系统稳定性与可维护性。
448 0
|
编译器 C++
VS /PROFILE(性能工具探查器)的使用
VS /PROFILE(性能工具探查器)的使用
511 0
|
网络协议
为何UDP协议不可靠?DNS为何选择UDP?
总的来说,UDP和TCP各有优势,选择哪种协议取决于应用的具体需求。UDP可能不如TCP可靠,但其简单、快速的特性使其在某些场景下成为更好的选择。而DNS就是这样的一个例子,它利用了UDP的优势,以实现快速、高效的名字解析服务。
768 14
|
存储 自然语言处理 前端开发
2025年大模型发展脉络:深入分析与技术细节
本文深入剖析2025年大模型发展脉络,涵盖裸模型与手工指令工程、向量检索、文本处理与知识图谱构建、自动化提示生成、ReAct多步推理及AI Agent崛起六大模块。从技术细节到未来趋势,结合最新进展探讨核心算法、工具栈与挑战,强调模块化、自动化、多模态等关键方向,同时指出计算资源、数据质量和安全伦理等问题。适合关注大模型前沿动态的技术从业者与研究者。
4220 9
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
1157 13
|
Windows
Windows操作系统部署安装Kerberos客户端
详细介绍了在Windows操作系统上部署安装Kerberos客户端的完整过程,包括下载安装包、安装步骤、自定义安装路径、修改环境变量、配置hosts文件和Kerberos配置文件,以及安装后的验证步骤。
2997 3
Windows操作系统部署安装Kerberos客户端
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
1429 7

热门文章

最新文章