《七周七语言》笔记——Ruby
不会有第二篇了,认真去学 Scala,将来若有需要可能回去碰碰 Rust 和 Scheme/Racket。
—— 2021-12-27
开始认真看《七周七语言》这书,主要目的是了解下各个编程范式在实践上的一些具体差别,同时了解一下各种语言的骚操作,如 Ruby 的模板元编程,scala 的 Actor,erlang 的……快速失败?Io 的基于原型的面向对象编程……总之按照书中的顺序挨个 peek 一下,首先是 Ruby。
考虑了很久,决定这书先放下,先学一门灵活又强大,既能用于实践也能用于各种形式抽象的语言,并对其进行深入学习,达到和 Java 一样的上手程度,能随手写出实例,也能拿来进行工程实践。
Haskell 先 pass,因为它难以用于实践;Kotlin 很有趣,let,apply 等方法精妙绝伦,但又略有工业气息(比如?语法糖,我还是希望它提供一个真正的 Optional),且进行函数式编程并不方便(写个柯里化的函数试试?);最终我还是选择 Scala,它的抽象能力足以模拟 Haskell 中各种骚操作,兼具面向对象和函数式编程特性让它在这两方面都可堪用,Actor 的并发模型也是我想关注的对象之一,而且在将来甚至还有实践意义,所以选择 Scala 是完全合理的。
第一天
我讨厌动态类型语言,讨厌鸭子类型(就如讨厌实用主义),因此对 Ruby 自然也没啥兴趣,但它的语法显然受 Perl 之类的影响很多(而函数命名则受到了 Scheme 的影响,从谓词后面带着的问号就能看出来),优美流畅如同自然语言,特别是单行的 if/unless,以及 while/until。其中 unless 等价于 if not。我始终想不到 unless 翻译成中文该怎么说,“若非”有点怪。
1 |
|
必须承认,这单行的循环还是有点麻烦的……正经人谁写循环啊。
然后,这是基本 for 循环——
1 |
|
这是 forEach 形式,语法非常像 Kotlin 的尾 lambda 形式——
1 |
|
足够做第一天的题目了,开始吧。
- 打印字符串”Hello, world.”。
1 |
|
- 在字符串”Hello, Ruby.”中,找出”Ruby.”所在下标。
这题首先想到的就是使用 find 或 indexOf 之类的方法,借助 tab 真让我补全到了——
1 |
|
- 打印你的名字十遍。
1 |
|
- 打印字符串”This is sentence number 1.”,其中的数字 1 会一直变化到 10。
利用字符串格式化。
1 |
|
- 从文件运行 Ruby 程序。
1 |
|
- 加分题:如果你感觉意犹未尽,还可以写一个选随机数的程序。该程序让玩家猜随机数是多少,并告诉玩家是猜大了还是猜小了。
这个语言的函数调用非常有趣,当把函数名写出来的时候,就是对函数的调用了。也就是说对于一个() -> a
的函数,其是直接进行了函数的调用,而非对函数本身求值。这在其他语言里是见不到的,Haskell 的 IO Monad 倒是在这上面和它现象一致,但本质肯定是不同的,在赋值时就能看出来了。如果想要在下面的 Haskell 里达到和 Ruby 一样的效果,需要a = unsafePerformIO randomIO
才行。下面的 a 是求值 randomIO 的结果,而非是 perform randomIO 的结果。
1 |
|
咳咳,总之专注题目。Haskell 的环境搭建太烦人了,依赖总是找不到,Stack 也总是配置不好,下次干脆 tm 用 purescript 算了。
这个问题需要将输入转换为整数,测试发现字符串的 to_i 方法能够进行转换。经过上面的描述,可以得到一个非常有趣(以及离谱)的解决方案——gets.to_i
。这种形式简直离谱😂。
1 |
|
我佛啦。
第二天
Ruby 的数组和 Python 的数组极为相似。形如1..10
这种形式的对象为Range
。数组可以通过 Range 来获得子数组。
1 |
|
有趣(但也挺 trival)的地方是,[]
和[]=
(设置特定索引的值)也是数组的方法。
1 |
|
有趣的地方是函数的多个参数是通过逗号分隔的……这么说我们如果要强调一个函数优先调用,得这么干——(puts 1, 2, 3)
而非puts (1, 2, 3)
。突然又像 Lisp 了,好家伙。
举一反三,我们定义数组的时候,其实是调用了这样的函数——
1 |
|
我实在不太喜欢这样……
哈希表的语法是这样的,好像和 Python 的类似。冒号前缀的数据类型称为符号,类似 Lisp 的 quote,或者其他 C 系语言的枚举。其通过 to_s 和 to_sym 方法可以和字符串互相转换,
1 |
|
前一天中{}包围的代码称为代码块。代码块是 Ruby 中的匿名函数。下面的代码顾名思义——
1 |
|
do-end 结构和代码块是否是同一种东西?
我们可以通过在运行时给 Integer 添加新的方法以构造我们自己的 time 方法,通过类似 Python 的 yield。yield 大概使函数变成了迭代器。
1 |
|
yield 本身不算难理解,可是它生成的是谁?self?i?如果是 self,对 i 的修改直接改变了 self?我们做一些测试——
1 |
|
看上去是后者,那 yield 是怎样“选中”i 的?最近一条表达式的返回值?哈人啊朋友!
Ruby 的带参数的函数定义同其他 C 系语言一致——
1 |
|
而关于代码块如何传递的问题,Ruby 对其的处理类似…找不到类似,总之很丑陋——给相应参数前加上&符号,再次传递时也是。
1 |
|
有趣的是,根据错误提示,代码块好像不属于函数参数的一部分,只能说十分奇怪了。
把 Ruby 后面的内容粗略翻了一遍……老实说没有什么我感兴趣的东西,而且在 kotlin 和 scala 里我已见过更漂亮的语法了,跳过!模版元编程什么的等 Haskell 再去学吧。下一个是 Io,一门简单的原型编程语言。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 协议 ,转载请注明出处!