Forwarded from dnaugsuz
()=>f() 里面的 f 作用域解析是动态的,所以不会找不到引用
在 Kotlin 写递归函数是可以的,可是这样的变量是不可能的,比如
在 Kotlin 写递归函数是可以的,可是这样的变量是不可能的,比如
val f: () -> Unit = { f() }
就不行error: variable 'f' must be initialized
val f: () -> Unit = { f() }
^
Forwarded from dnaugsuz
typealias PredicateOn<T> = T.() -> Boolean
typealias Producer<R> = R
fun <R> retry(n: Int, terminate: PredicateOn<T> = { true }, op: Producer<R?>): R? {
for (_i in 1..n) {
val res = op() ?: return null
if (terminate(res)) return res
}
return null
} 这么写岂不是也可以……
骚操作一点(不建议)甚至可以这么写
fun <R> retry(n: Int, terminate: PredicateOn<T> = { true }, op: Producer<R?>): R? {
for (_i in 1..n) {
val res = op() ?: return null
res.takeIf(terminate)?.let { return it }
}
return null
} 写成Java一样意义不明的风格是哪般……
真鼓吹数学的人都去学抽象代数机器证明了,次一点的也搞范畴论Monad学descriptive甚至逻辑式去了,应用编程就写好看点,为什么起名字喜欢起数学糟粕形式的名字……
难道还真应验了王某人的那句话『你越是看不懂越觉得自己智商低、越觉得我牛逼』……
也可以 functional inline
加个 inline 就行,然后如果报错就继续加 crossinline……
Forwarded from dnaugsuz
from re import sub
print(sub('p', 'q', input())) 嗯…… 其实应该用
str.translate 的Forwarded from dnaugsuz
AWK 里是 gsub,我估计它是 generalize subtract 的缩写
至于为什么开始少写了一个参数,我忘记了是应该有 pattern-replacement 的。
光是靠
至于为什么开始少写了一个参数,我忘记了是应该有 pattern-replacement 的。
光是靠
sub(regex, replacement, text) 好像是不可以,毕竟你不能给一个子 pattern 指定多个 replacement。Forwarded from dnaugsuz
在 Kotlin 里,这个语法是这么表达的(举个例子):
使用的方法是 Kotlin 的 Progression,趋势数列,也就是可以有(负数) step 的区间迭代
val text = "hello"
val reversed = text.fold(StringBuilder()) { sb, c -> } // 打住,好像我不是这个意思……
val reversed = StringBuilder()
for (charIndex in text.lastIndex downTo 0 step 1) // 这就是 text[beg:stop:-1] 的意思,step=-1 -> downTo 1
reversed.append(text[charIndex])
println(reversed) 使用的方法是 Kotlin 的 Progression,趋势数列,也就是可以有(负数) step 的区间迭代
Forwarded from dnaugsuz
一般来说好像不要用这个语法,因为不知道它的人会感到困扰,如果是实践就用 reversed 吧。
Forwarded from dnaugsuz
不是吧,是不是
另外
lambda x: x 的意思啊?rev rev id 可是逻辑式编程和计算机辅助定理证明的入门例子呢另外
::n 好像这个语法也被 TCP 使用了?那它就更不该经常在实际项目里用了,切记啊。Forwarded from undefined + 1 = NaN
那
k=lambda x: x[::-1], k(x[::-1]) 呢?Forwarded from dnaugsuz
不是一样吗?而且这里 k 应该叫 f 更好的
然后那个 Lambda 后面不是该跟表达式,表达式后面又有
应用序Y组合子(Applicative Order Y Combinator) 里我喜欢把别人经常叫 x 的函数给叫成 c 或者 k,我认为那是 continuation 之类的意思,看起来好高级呢。
(f str[::-1]) where
f = \s. s[::-1] 然后那个 Lambda 后面不是该跟表达式,表达式后面又有
',' 是啥意思……Python3 没这语法吧应用序Y组合子(Applicative Order Y Combinator) 里我喜欢把别人经常叫 x 的函数给叫成 c 或者 k,我认为那是 continuation 之类的意思,看起来好高级呢。
Y = \f. (\x. f (x x)) (\x. f (x x))Lambda 演算很长我这里不能细说,总之
My_Y = \f. (\c. f (c c)) (\c. f (c c))
\formal. body 是对 body 的一种抽象(比如,把x装进冰箱里,其中x是一个物体,装冰箱=\x. ……)、(f x) 的项目并列是对抽象 f 的一种应用,也就是提供它的参数,一般lambda演算都是单参+高阶函数(返回函数的函数)实现多参函数的,用『currying』的方式逐步填完所有body里依赖的参数。Forwarded from dnaugsuz
>>>
而且 Python 里 Lambda 好像不能递归引用自身,Kotlin 里的 Block 也一样(不知道是不是叫 Block 呢)(毕竟它主要是作为「函数值」的,当然不能引用自身啊)
k=lambda x: x[::-1], k(x[::-1])
NameError: name 'k' is not defined而且 Python 里 Lambda 好像不能递归引用自身,Kotlin 里的 Block 也一样(不知道是不是叫 Block 呢)(毕竟它主要是作为「函数值」的,当然不能引用自身啊)
呃我就照着你说的一段段回复吧:
> @duangsuse 不好意思,可惜[不大会 kotlin](https://zhuanlan.zhihu.com/p/32242763)。关于`用("bb")替换前(3)个("aa")`这样的语法,之前只是想在现在大多数语言的方法定义(仅支持参数位于末尾)的基础上作一个改变(进?),与其这样定义:
>
> ```python
> def replace(old, new, max):
> ...
> ```
**我的观点:这绝对不能算作是改进,尽管它往往不会与绝大部分语言的原文法冲突也不能。(JavaScript在限制不换行的情况下也不会)**
就实现可能性上,一般我们认为 `someFunc(a0)aname1(a1)...` 这样的模式,当然是可能与绝大部分只需要 *一个参数*(但不至于与需要一个 `tuple` 的函数)相冲突的(我是指对于老思路那些 *不需要* 这种特性定义的函数)
**但是**,如果文法上直接换成这种形式定义,其实也没什么问题(看刚才我写那Kotlin就知道的确是没啥问题,因为按Kotlin语法 `f()` 完后的后继只能是[中缀](https://kotlinlang.org/docs/reference/grammar.html#disjunction)如 `.` `+` 或另一个前面肯定没名字的后缀如 `()`、看[Z语言](https://zhuanlan.zhihu.com/p/40356993)也知道的确是没问题)。
首先我相信绝大部分静态类型检查的编程语言设计者,尤其是重视代码一致性的程序员都讨厌一些比较容易混淆的语法,尽管也有许多人喜欢 Ruby、Python 的 "keyword arguments" `def dig_a_hole(depth: 1, label: 'hole'); puts"$label $depth"; end` 这种。
包括我之前在 [以绝句语言翻译](https://t.iss.one/dsuse/12118) 你之前翻译那个 Swift 的时候我都这么想,如果参数列表可以随便hack成那样:
```
func 问好(_ 人: String, 在 日子: String) -> String {
return "吃了么\(人), 今天是\(日子)."
}
问好("小黑", 在: "周三")
```
如果没学过,哪怕是作为一个初学者你能明白这TMD是在做什么吗?下划线是什么意思?『日子』和『在』有啥联系?还是区别?反正我是看不懂。
>介于我之前发了很多 t.iss.one 的链接估计都没人点进去看,我摘一点吊吊胃口
```swift
“func 统计(得分: [Int]) -> (最小: Int, 最大: Int, 总和: Int) {
var 最小 = 得分[0]
var 最大 = 得分[0]
var 总和 = 0
for 分 in 得分 {
if 分 > 最大 {
最大 = 分
} else if 分 < 最小 {
最小 = 分
}
总和 += 分
}
return (最小, 最大, 总和)
}
let 结果 = 统计(得分: [5, 3, 100, 3, 9])
print(结果.总和)
print(结果.2)”
“绝句里单引号是文档,可以在工具里看到。”
“一个类/物的类型参数可以直接加入文档,参数和返回值的文档可以直接加在前面也可以独立加”
“和Kotlin,也是Markdown的”
事 统计(得分:组<数>):‘最小、最大、总和’ 元三<数、数、数> 为
对得分里的分,
判分, “一时间我也找不到更好的方法把「对」和「判」连在一起”
它大最大,最大 = 它。 “「它」是此分支局部的”
它小最小,最小 = 它。
否则,效果。
上皆,总和令置为「+分」。
回元三(最小、最大、总和)
这里,
变数 最小 初0;变数 最大 初0;变数 总和 初0 “不是一般的编程风格,但不置可否。”
“这个版本里,暂时我不会把对「变(属)(名)初(言)」的修改加上,请兼容前面的一部分。”
```
我觉得这样的语言对所有,甚至包括 mother tongue 是 English 的人都是莫名其妙的,而且类似的语言不在少数。
这就是一个观点的问题,也就是『脚本化』还是『规范化』两个互斥的方向,可能相关的你可以看看冰封哥的 [形式验证、依赖类型与动态类型](https://zhuanlan.zhihu.com/p/50792280)
拿一个最简单的例子:比较 Bash 和 Python
当然其实 Bash 作为一门 Shell 语言也是有『[形式化](https://my.safaribooksonline.com/book/operating-systems-and-server-administration/unix/1565923472/syntax/lbs.appd.div.3)』(除了heredoc字符串语法)的语法定义的。
可它的可读性、易学性真的不能与Python相比,或许你会说它们根本不一样,但 Bash 的确是程序设计语言,不过没 `csh`、[elvish Shell](https://elv.sh/) 那么明显而已
比方说呢?Bash 的函数不能有形式化参数,只能在函数体里 `$1 $2 $3` 引用,而整个脚本居然也能把 shell 的参数以 `$0 $1 $2` 引,好像 `bash` 命令是个函数一样、尽管有作用域,函数里定义的变量默认是全局作用域还需要 `local` 来定义一个「局部的」、尽管函数带括号,调用都是 `f x y` 这种形式,而且三种引号 `''` `""` `\`\`` 给人感觉简直难以区分、file pattern 的直接裸写有效也让人经常在参数里包含一些特殊字符时遭逢莫名其妙的问题,更别提 `|` `>` `<` 符甚至 `2>` `2&>` `<&-` `n<&-` 这样看了文档也好长时间才能记住的『重定向』,以及莫名其妙的 +-*/ `&& ||` `declare` 和所谓的 `[]` test 这种加不加空格都有区别还有 N 种写法的『命令』了。
再比较Python和Java,就不提属于运行时特性的 `eval` 了(而且 Java 也完全可以利用 compiler API 或者 `ClassLoader` `defineClass` 动态编译加载到虚拟机来执行代码),不知道有没有Python能吐槽Java的某一点
介于 Java 1.7 都有 try-with-resources 了,他们没法吹 Python 的 `with ` 这种“更自然”的 try-with(当然 Kotin 可以光明正大地藐视所有这样的『脚本语言』,因为它的标准库里[一个 `use` 函数](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/use.html)**就定义了这个被Python视为『语法』的东西,而你甚至不需要知道那个语法是 `with res as name:`**,IDEA 里 <kbd>Ctrl-Q</kbd> 一下就能立刻用上)(原来绝句也有 `尝试文件去开()成某书……`,这么一写我觉得不能有了)
我想他们要吹的肯定是 Python 的动态类型、duck typing,这样你就可以随性地使用任何有 `size` 属性的对象上的 `size` 来取长了,而 Java 不仅每次写 `Something something = new Something();` 麻烦还要各种写 Adapter boilerplate 来解决这种问题,Oh yes my dear Python。
我就不吐槽 Python 那毫无规章的『元方法』如 `len`、`repr` 和莫名其妙的『面向对象』设计以及基础库了,Ruby程序员一直在吐槽。
它的 `:` layout 式语法算是一种创新,可仅止于此,其他的设计都是极度三八极度脚本化的,简直恨不能为Bash,想想Python3都忍不住跨大版本都快抛弃向前兼容了还没改过来,我真是极度地感到惋惜。
例如Kotlin这样的语言更不可能看上这种语法,因为它可能与 `infix fun` 存在语义上的冲突,即便这种冲突可以解决但那可能会给语言的使用者制造一些问题(比如,随性定义了一个使用常见介词的函数,结果与其它函数库的版本冲突……实践上这尽管能解决但不该有这种问题)
至于如果一定要说静态类型的好处,其实封装、抽象、继承、多态、fail-fast 我就不用说了,引用冰封哥的一句话(貌似是,忘记从哪看的了):
> 一个多态就能吊打它们了
没错,一个参数类型式的多态就比它们强太多了,不论类型是否一定要显示标明,静态类型都能在更早的时候确定更多的信息(不需要很复杂的推导算法),基于这样的信息你可以无开销地弄出许多DSL和针对特定输入的优化版本程序,或者仅仅只是静态的 optional arguments 也很好。
**我的另一个观点是,一门好的编程语言不应该能让它的使用者写出不好的代码,哪怕只是可能。**
> 允许这样定义(暂不讨论关键字):
>
> ```python
> def 用(new)替换前(max)个(old):
> ...
> ```
>
> (无意尽量避免括号等)
貌似无论是 Python 还是 Ruby 上这种修改都没有太大问题,不过 optional arguments 和 keyword arguments 就不应该在这种形式支持了,如果更严格我觉得使用这种形式的 Python/Ruby 就不该有 optional/keyword 了,而且 Ruby 的 `&op` 块参数也要好好考虑怎么弄好。
```ruby
def call_with_1p(n, &op); yield(1+n); end
call_with_1p(0) { |x| puts x }
```
不过介于 Ruby 其实已经支持这种形式(出于它有 `f a b` 这种无论是我还是 Haskell 大佬看了都会绝得自己酸死的 Bash 式语法)
不过要写出来是比较麻烦的,类似 trie 树地,它要判断自己的参数是不是对象 `替换前` 后面的后面(就是下一个参数)又是不是 `个` 什么的,比较麻烦。
但如果你觉得 `用(new)替换前(max)个(old)` 可以实现为 Keyword arguments 的形式(它在定义里表达原 `用(x, 替换前: max, 个: old)` 使用参上),我觉得相对比较好实现,不过我显然不能帮你实现(还有绝句解析器要写啊)
> > 我觉得在语言都还没有定好的情况下是不应该太考虑API的,不是不应该考虑,但是语言……基础的定义、控制结构,已经确定,这必须是前提吧。
>
> 个人(只学过一点 PL 皮毛)觉得 api 的设计(比如上面的语法改变)会影响语言本身设计。而且也许有时牵一发动多处,比如[楼上](https://github.com/program-in-chinese/overview/issues/11#issuecomment-569463904)末尾牵涉到类型转换,等等。英文 api 已经基本约定俗成了所有参数在方法最后声明,因此这方面并无什么发挥空间。
是的啊,所以我刚才没说得太绝对,我自己也深有体会,比如写这个回答的时候就因为提及了Kotlin标准库的一个设计,我决定改掉一个语法,之前我以绝句[重写了某JavaScript ES6的代码](https://duangsuse-valid-projects.github.io/Share/%E7%BB%9D%E5%8F%A5/%E7%BB%9D%E5%8F%A5%E8%AF%8D%E6%B3%95#%E7%A4%BA%E4%BE%8B)后我又改了绝句的一个「构词」。
而且说点不相干的,你个人研究中文编程也有几年了吧,我能给最大的建议就是:多『学』几门语言,好好斟酌比较一下它们的区别(这是别的方法无法替代的),总结出点类似「顺序、判断、重复」这样的东西来,也不必学多高大上写 LLVM 编译器前端 `IRBuilder`、JIT 什么的,就琢磨一下语言的设计就挺好。
> 如果,支持上面的方法定义`用(new)替换前(max)个(old)`,以及`如果(...)xx`这样的方法命名,代码写出来也许是这样的:
>
> ```java
> 文字 问好 = "你好"
> 数[] 号码 = [1, 2, 3, 4, 5]
>
> 问好 = 问好.用("吃了么")替换("好")
> 号码.如果((数) -> 数 > 4)移除
>
> 对(号码)中的(某数) { // 遍历这样看起来有点像是方法调用
> 说(问好 + 文字(某数)) // 假定强制转换必须显式
>
> 如果(某数 % 2 == 1) { // 与`如果()xx`方法看起来有点像
> ...
> }
> }
> ```
>
> 写出来之后会发现更多问题(个人短期内无打算深入)
呃这样我没啥可说的,我贴一个自己[之前](https://t.iss.one/dsuse/11776)写的代码(当然也有很多在我的笔记上没发),以及一个以目前绝句设计能有效的代码吧
```java
把(这人.的(朋友们).中(所有(名字.以("abc").起始().的()))).都拿去(用户表::删掉);
从(1).数到(100, (它) -> {
若((它/2).为零(), 向(终端).写("偶数"))
.否则(向(终端).写("奇数"));
});
Consumer<?> 不可能 = (Object _) -> { throw new ImpossibleException(); };
判断(他.的(名字),
倘若(它.是("蔡徐鲲"), 向(它).致敬()),
倘若(它.是(在(iKun.映射到(IKun::名字)).中()), 向(终端)::写),
否则(不可能));
```
```plain
判他的名字,
是"蔡徐鲲",我致敬(它)
在 iKun映至「的名字」“其实不该每次去投至”,输出写它
否则,不可能。
```
```plain
引记法 绝句.严格中文 「以」
引记法 绝句.集合 「滤」
变文 问好 初 "你好"
“「初」不是随便设计的,我有其它考虑这里不提”
“如果是常量可以用「常文」或「量」”
“ 量 问好:文 = "你好" ”
量 号码 = 动组一(1、2、3、4、5)
“Mutable Array (而非 Array<out T> 那种,类型系统一样但提供了一个简写法)”
“ inline fun <reified T> im(vararg items: T): Array<out T> = arrayOf(*items) ”
“绝句不支持一至九开头是因为数字也可用它们表示,”
“这也不是随便设计的。”
“介于绝句不是『脚本语言』以及例子的完整性”
事 入口() 为
问好 = 问好去置换("好"到"吃了么")
“量 某表 = 表一("天"到"地"、"海"到"空"、"大陆"到"长空")”
“解对(1至10)与(1止11)里的(甲、乙),断言(甲是乙)”
“这是一般用法,「对」是存于 绝句.额联 的中缀记法”
问好 = 问好以("么?")去置换("么")
“这是「记法」的用法,当然也可以显示用「去以」而不省略访问符”
“你上面的代码好像写错了,暂且把『移除』当成 "xs[i] = null" 处理吧”
对号码的索引里的针,
若号码[针]大4,号码[针]=空。
“这是绝句第一版的风格,和Kotlin差不多;到时候有了 `存储<值者>` 抽象就不一样了”
“我们也可以用函数式的风格,但这里一般风格更好,尤其是现阶段绝句没任何优化靠Kotlin的情况”
对号码滤出不空里的,
说("${问好}${它去化文()}") “去化文也不必写”
若它之为奇数,效果“啥都不做”。
扩物 数 为
记法「之」的量 之为奇数 取者,我取取余(2)是1。 “我又决定绝句要去掉 % 中缀符转用记法了”
```
> 之前写过一点关于[语言设计和 api 的顺序](https://zhuanlan.zhihu.com/p/85081589),现在仍觉得,如果首先从语言设计(甚至实现)出发,往往会出现削足适履的情况。越早编写接近实用的例程,越能发现语言设计的缺漏和可优化之处。因为实用(尤其是与实际业务相关的,而非纯算法)代码将是语言推广后存量比例最大的。而接近实用意味着至少是一小部分api 设计,以及一定的标识符命名风格。
所以你要写啊,尽管许多语言的入门示例足够概况,但那远远不够啊。
> 对[楼上](https://github.com/program-in-chinese/overview/issues/11#issuecomment-569958947)的例程,个人(也许对目标人群有不同设想)第一眼感觉,“听去数一”,“解对”,“去化数”, “次里的”等等难以一目了然。另外,逗号、分号、句号、双冒号、顿号、波浪号等等似乎都是语法因素,也许会增加学习和使用负担。
其中 `听去数一` 的 `去`,其实我也很没办法,毕竟为了语言的一致性「去」访问符根本无法省略、`解对` 是我刻意那么弄的,本来也可以遵循Kotlin仍用 `对`,它就是来描述 `for ((index, item) in list)` 的这种。
此外「次里的」是你理解错了(因为绝句是期望不带空格的风格的),其实它是 `对(n次)里的` 的意思,这里用「解对」的确是令人困惑,但你同时去掉「解」和后面的「_」后它依然是工作的,逗号后面的 body 里多一个叫「它」的变量而已。
知道「去」是 `.` 的意思你就知道 `听去数一` 其实是访问 `听` 对象上的 `数一` 方法了,在 Java 里这是 `input.nextInt()`、`去化数` 则是 `toInt()` 的意思。
>逗号、分号、句号、双冒号、顿号、波浪号都是语法因素
所以说才叫『中文编程』啊,你试试就会知道只要输入法质量过关,没有任何问题。
>『某』 为可不带空格的『角括名字』、「某」 为中缀表示、【某文形】 为标记修饰、〖某文形〗 为块参数列表
https://duangsuse-valid-projects.github.io/Share/绝句/绝句词法
学任何语言都是要学这些表达形式的,我在设计时刻意没看Kotlin的词法规则,就是为了能设计出更贴切中文的文法表达。