/tmp/duangsuse.sock
23 subscribers
303 photos
3 videos
92 files
337 links
从 duangsuse::Echo (@dsuse) 跟进出来的分支,将在作者恢复原帐号访问的时候合并删除。
Download Telegram
Forwarded from Deleted Account
比如说 listOf(1, 2, 3).fold(0) { acc, x -> acc+x }
从函数式的角度,initial 和 accumulator 是变量、op 是一个闭包(在我们看只是函数),整个 fold left 在算法过程(面向对象的)里是一个循环
fun <T, R> Iterable<T>.fold(initial: R, op: (R, T) -> R): R {
var accumulator = initial
forEach { accumulator = op(accumulator, it) } //loop
return accumulator
}

从面向对象的角度,你也可以弄出一个『类』版本的 interface Reducer<in T, out R>,抽象出最关键的 accept(T) 和 finish(): R
然后就可以有 class JoinFold 把这个 initial, accumulator 变成 private val (私有属性),op 提升一层变成 this 上的函数(也就是方法)
就得到了面向对象版本的 listOf(1,2,3).fold(JoinFold(0, {this+it})
#Haha #Low #China #huawei 呵呵,这种自 high 都能做得出?
Forwarded from 永久封存 | Yuuta 台 | 😷 #Pray4Wuhan (Yuuta | 武汉加油 | 😷)
https://t.me/himself_65/340

华为对苹果的最大一次胜利:日前,欧洲统一了手机借口标准,欧盟投票通过,未来在欧洲销售的手机都必须采用统一的华为口式借口(Type-C)。
谷歌对苹果的最大一次胜利:日前,欧洲统一了手机借口标准,欧盟投票通过,未来在欧洲销售的手机都必须采用统一的谷歌口式借口(Type-C)。
小米对苹果的最大一次胜利:日前,欧洲统一了手机借口标准,欧盟投票通过,未来在欧洲销售的手机都必须采用统一的小米口式借口(Type-C)。
戴尔对苹果的最大一次胜利:日前,欧洲统一了手机借口标准,欧盟投票通过,未来在欧洲销售的手机都必须采用统一的戴尔口式借口(Type-C)。
苹果对苹果的最大一次胜利:日前,欧洲统一了手机借口标准,欧盟投票通过,未来在欧洲销售的手机都必须采用统一的苹果口式借口(Type-C)。
非洲猪瘟也是中国设计的,没控制好而已 🌝
#NSFW 好像是 porn 群呢 @newsob
好了,Parser.kt 基本出山 🤔
Forwarded from Deleted Account
val dict = TriePattern<Char, String>().apply {
mergeStrings("hello" to "你好")
mergeStrings("world" to "世界")
}

val noun = Repeat(asList(), dict)
val pharse = JoinBy(Decide(elementIn('0'..'9'), elementIn(' ', '\t', '\n', '\r')), dict)

>>> pharse.rebuild("hello world")
res21: kotlin.String? = hello world
>>> pharse.rebuild("hello world a")
res22: kotlin.String? = null
>>> pharse.rebuild("helloworld")
res23: kotlin.String? = hello
>>> noun.rebuild("helloworld")
res24: kotlin.String? = helloworld
>>> noun.rebuild("hello world")
res25: kotlin.String? = hello

>>> pharse
res19: JoinBy<kotlin.Char, kotlin.Char, kotlin.String> = {Path{h=Path{e=Path{l=Path{l=Path{o=Bin[你好]{}}}}}, w=Path{o=Path{r=Path{l=Path{d=Bin[世界]{}}}}}}}([0-9]|(' '|'\t'|'\n'|'\r'))

>>> pharse.read("hello world")
res20: DoubleList<kotlin.String, kotlin.Char>? = Tuple2(first=[你好, 世界], second=[ ])
Forwarded from Deleted Account
这次的解析器框架是纯 one-pass 的,靠 Contextual, Peek, Pipe 的组合完成附加的处理过程,不存在 mark/reset 和 k>1 的情况,但完全可以兼容那种好像需要 lookahead 的情况,所用的数据结构更贴近编程语言而不是一些栈和自动机。

框架的 Pattern<IN, T> 是全泛型、面向一切序列(Iterator、InputStream、Slice也即List、Array、CharSequence)的,这意味着你甚至可以用它抽提反射元数据或者 Array<out String> 里的信息

为了方便测试以及一些其他的考虑,解析器框架不止负责数据的提取,还负责管理提出的数据,并且能够(允许在修改变动后)重新把它们架构回输入数据(rebuild),这可能是比较独特的一点——其他方法都仅仅只有提取基本值的解析器,不包含对提出数据的建模,但 ParserKt 利用 Tuple 和 Fold 两个扩展完全包办了整个生命周期。

就错误处理方面,ParserKt 的 Pattern<IN, T> 返回 null 代表解析失败,目前支持的错误策略是 ErrorListener { onError: ActionOn<Feed<*>, IN> } 和 clamWhile(pat, defaultValue, message),对输入的扩展方法,大家都知道的,随便里面分配个 MutableList 引用加给 onError 闭包。

行号当然必须支持啊,就是 Input<T> 的扩展 CharInput 有。CRLF 也是可以计入的,也就是说 Kotlin 实现语法需要的特殊处理,也没问题喽。

而且提供了一个简单、带注释的中缀解析器实现,以及字典树(方便解析关键字什么的)

代码里有用到 Kotlin 的 intersection upper bound (在 extension fun 的 receiver 里)
@UnsafeVariance (Seq 和 Decide 的兼容)

感兴趣的大佬可以看下
同样的东西,这是我写的第十遍。
Deleted Account
val dict = TriePattern<Char, String>().apply { mergeStrings("hello" to "你好") mergeStrings("world" to "世界") } val noun = Repeat(asList(), dict) val pharse = JoinBy(Decide(elementIn('0'..'9'), elementIn(' ', '\t', '\n', '\r')), dict) >>> pharse.rebuild("hello…
val ints = Seq(::IntTuple, item(1), *Contextual(item<Int>()) { i -> satisfy<Int> {it>i} }.flatten().items() )

>>> i.rebuild(1,2,3)
res1: kotlin.collections.List<kotlin.Int>? = [1, 2, 3]
>>> i.rebuild(1,2,1)
res2: kotlin.collections.List<kotlin.Int>? = null
>>> i.rebuild(1,0,1)
res3: kotlin.collections.List<kotlin.Int>? = [1, 0, 1]

val xsv = JoinBy(elementIn(',',':'), Repeat(asString(), !elementIn(',',':')))

>>> xsv
res1: JoinBy<kotlin.Char, kotlin.Char, kotlin.String> = {{!(','|':')}...(','|':')}
>>> xsv.rebuild("adadc,dasda,de")
res2: kotlin.String? = adadc,dasda,de
>>> xsv.read("adadc,dasda,de")
res3: DoubleList<kotlin.String, kotlin.Char>? = Tuple2(first=[adadc, dasda, de], second=[,, ,])
>>> xsv.rebuild("adadc,dasda,de:dasd,fsd:f") { second = second.mapTo(mutableListOf()) { if (it == ':') ',' else it } }
res4: kotlin.String? = adadc,dasda,de,dasd,fsd,f
又新加了个 elementIn('A'..'Z', 'a'..'z', '0'..'9') or elementIn('_') “逻辑连接符” 支持
看起来 ParserKt 的确是能够用来辅助设计语法,但要想优雅地用于实际目的,很难……
这时候 one-pass 和 rebuild 反而成为了两个傲娇的特性,就比较难受……
Seq 不能用,得用 SurroundBy
Seq(::AnyTuple, *(item<Char>()-'*')) 还有这种用法表达一个 Until pattern……
也是无奈啊
如果允许添加扩展方法,这其实不是多困难的,可在没 IDE 的情况下我不方便做这些非核心的工作……
/tmp/duangsuse.sock
看起来 ParserKt 的确是能够用来辅助设计语法,但要想优雅地用于实际目的,很难……
不是很难……我相信,只是还有点距离…… 初心和理论是好的,就是实现上后来有点小偏差……

现在的 ParserKt 虽然对辅助语法设计有很好的作用,也没见很严重的 bug,但写出来的代码依然不是很易读……
有点头疼,undecide 和 unfold 到底是如何如何…… 那么多 extension 怎么整理……
还是先来自 high 一下吧,本苏写的这个 ParserKt,虽然只有 700 行,绝对可以说是发挥了 Kotlin 的极限……之前的一点,大部分都是不太常见的编程方法,以及 Kotlin 1.3.6 的新特性

反正平常只写那么一两个应用的开发者,肯定是写不出来的

用这个框架写的计算器,只要 30 行就能同时支持优先级、动态中缀定义、REPL 什么的,而且还包含字典树等高级操作