/tmp/duangsuse.sock
23 subscribers
303 photos
3 videos
92 files
337 links
从 duangsuse::Echo (@dsuse) 跟进出来的分支,将在作者恢复原帐号访问的时候合并删除。
Download Telegram
🤔 看起来稍微好了点,可惜还是感觉有点复杂
不过这可是 ParserKt 啊!这么一点代码也支持了 rebuild 和镇静解析策略,提供了 error message,我也满足了。
比靠 parser compiler,生成一堆不知道是怎么工作的代码要强。Haskell GHC 的解析器都不支持镇静策略呢,输入稍微有点错误就全局爆炸。
This media is not supported in your browser
VIEW IN TELEGRAM
duangsuse 你真机智,那么我们来休息一下算了,别写代码了……
我们最后玩一个梗吧,
李明开始喜欢上了坐在教室一隅的小静
现在咱有字典树了,看看怎么提取这个句子结构
李明(r) 开始(pre) 喜欢(v) 上(b) 了(b) 坐(v) 在(pre) 教室(n)一隅(n) 的 小静(r)
r=代词、引用
n=名词; v=动词
pre=前导
b=补语(迫真)

李明(r) 开始(pre) 喜欢(v) 这是一部分
(r) (v)
(v) 前面可以有 (pre)
(v) 后面可以有 (b), (pre)

(v) (pre)

坐(v) 在(pre) 教室(n)一隅(n) 的(c) 小静(r)
(n) (n) 是名词连接

艹写不下去了

enum class WordKind {
Ref, Verb, Noun, Pre, Mid, Unknown
}

typealias Word = Pair<WordKind, String>
val dict = object: TrieReplace<Word>() {
override fun from(path: String) = WordKind.Unknown to path
}.apply { }

算了不写了,狗命要紧
第975884位,但是只要我活着,就没有影响!
This media is not supported in your browser
VIEW IN TELEGRAM
PPOP 😂
PPOP SURDIES CCDP SJIT
向不优雅的东西告别吧。
Forwarded from Deleted Account
艹春秋大梦破灭
Forwarded from Deleted Account
最底层的 SatisfyPattern 可以取 negate,我以为编译期就可以做外层包装 pattern 的 operator not 支持的
Forwarded from Deleted Account
既然不支持,我不知道该怎么样了
Forwarded from Deleted Account
越写越复杂,干脆不支持,手动 not 最里面那层 satisfy 好了
Forwarded from Deleted Account
fun digitItem(digit: SatisfyPattern<Char>) = Convert(digit, {it-'0'}, {'0'+it})
val digit = digitItem(elementIn('0'..'9'))
Peek(!digit) {0}.clam("no octal notations")
我就想能用这个
老实说,如果 ParserKt 不支持 rebuild 那这个泛型没有问题
可是支持了,所以不能瞎弄了……
Forwarded from Deleted Account
这还是我第二次破灭了,上一次是以为有了 always(T) SurroundBy 能不靠 Pair<ConstantPattern?, ConstantPattern?> 的 null test
可是实际上 ConstantPattern 的 T 值也要用来 show,所以不能用 always(value) 来随便提供一个 Unit 值,哈。
我还以为是优化的
Forwarded from Deleted Account
越写泛型参数和子类型越多,越发现 Kotlin compiler 的精妙
有时候我以为是 Kotlin 类型推导错了,后来发现其实是自己的参数顺序、类型参数什么的搞错了
如果不知道类型推导有什么意义是不会领悟到这一点的,真是不容易啊
很久以前我以为类型推导就是 var pair = Pair(1, "string"),所以很容易做

如果不写这种高复用性的框架,还真是不知道类型推导可以有多方便
This media is not supported in your browser
VIEW IN TELEGRAM
我该怎么办
ParserKt 灵感智销,请帮帮我们
ParserKt 的底层 Feed 抽象出了一点小问题,就是基于『所有 peek 最终目的都是 consume』这个假设现在不成立导致的,真的让人头疼
Forwarded from Deleted Account
从算法学啊,当然 Java 的结构是面向对象

类 包含许多字段(field) 和关于 this 的行为(称为方法,method)
this 是主语,field 是代词,装着的是某个类的对象的实例的“状态”,method 是动词。
class Dog {
String name;
public Dog(String name) { this.name = name; }
void bark() { System.out.println(name+" barks."); }
}

上面的例子里,this 是主语『狗』、name 是代词(狗的)名字、bark() 是动词『叫』
状态是什么?比如一个 int 可以是 0,1,2,... 某个 field 可以取为这些不同的 int 值,就是“保存了状态”

如果你用 IDEA 这可以 Alt+Insert 自动生成不少结构比如 constructor(new Dog() 的那个)、equal/hashCode/toString 什么的。
如果你用 Kotlin class Dog(val name: String) { override fun bark() = println("$name barks") } 就可以定义这样的类。
个人建议只要有可能 Java 入门立刻换学 Kotlin。

类是对一类对象的泛化,比如狗这类东西,就可以有 new Dog("王叔家的狗")new Dog("二爷家的狗")

而刚才提到一堆 new 的东西,就是对象(object) 了,它们是一些比类更加特殊化的东西,比如世界上所有母亲都是母亲,而你妈是更特殊化的母亲。
狗这种东西有名字,也可以叫(向控制台“叫”出一段文字(String)……)。
但是我们把让某个狗叫的这种行为封装成了需要一个『狗』的 this(实例,instance)的行为
使用你的『抽象(我们叫类库)』的程序员,不需要知道一个狗到底怎么叫,只需 dog.bark() 就可以了,

我们把这种 class (methods, properties), object instance 的模式称为『封装』。

Java 里你能 class Foo { static int n = 1; } 定义『静态』的方法和字段/属性,但正统的面向对象里是不存在所谓的『静态』成员的,在 Kotlin 里,成员(字段/属性/方法)是这么定义的:
class John {
static String name = "John"; // 字段
static int getAge() {} // 属性是 getXXX / setXXX 形式的 "propety accessor",方法的一种规范形式
static void setAge(int age) {}
static void call() {} // 方法
}
// In Kotlin
object John {
val name = "John"
var age: Int = 0
fun call() {}
}
Kotlin 里面如果不用 get() = valueset(value) {} 的话一般都有所谓的 "backing field",但 Kotlin 是不太重视所谓 field 的,
一个好的 Java 程序员应该重视代码的封装能力,如果你把 field 暴露出去,别人的使用都是 obj.field 形式,如果后来你要再加额外逻辑 e.g. 取的时候 println 呢?就不可以了。

Kotlin 里面的 object 在许多 Java 程序员嘴里都是 singleton instance,而且为了实现这个东西 Java 从程序员到 2020 年了还要写老长一段代码,10 行的效果和 Kotlin 里 5 行能完成的没区别,所以说能用 Kotlin 尽量用 Kotlin,利于个人发展。

Java 里,成员还有可见性(visibility)或者说可访问性(accessibility)
private 成员是一个类私有的、protected 成员是类和 extend 它的类共有的、public 成员是整个世界共有的……

这么说吧,在另一门面向对象的编程语言 Ruby 里,private 成员只有一条规则:它的主语(receiver) 也就是 this,不能被显式指定
比如我们举个骂人的例子(开心就好),哔~你妈 的主语『我』,Java 里是 this
它可以是隐式的,但在如名字与参数冲突的时候也可显式写出来。
小明哔~你妈
的主语『小明』,又是另外一个对象,这就要求小明开放了 ”哔~某人的妈“ 这个行为
但小明 private void fxxk(Person other) 了这个行为,你就不能让人家去哔妈了,这是人家”私下“的事,只能人家在自己的领域自己决定。

再比如,如果有一类事情私下里都有一些共通的行为,这时不必让他们每个 class 都去 private method 一次,可以弄个共同的超类,再添上 protected method,这样就实现了在它们这些 child class 里这个操作的代码复用

import java.util.Date;
class Logger {
protected void printHead(String head, String text) { System.out.pintln("["+text+"] "+text); }
}
class TimedLogger extends Logger {
void printLog(String message) { printHead(formatTime(), message); }
private String formatTime() { return new Date().toLocaleString(); }
}
class PersonNameLogger extends Logger {
void logPerson(Person person, String message) { printHead(person.getName(), message); }
}

三种 Logger 都有通用的子程序 printHead 来输出一行 [head] message 这样的东西,然后子类又都依赖这个子过程组织成新的程序
这个子过程,本身是不能被”外部“,代码的纯用户访问到的,也就保证了未来的维护不会导致一堆依赖你代码的程序员找上门来,说”这个为什么又不能用了"、“你早不说是内部的过程,我们都已经用滥了”。

——
面向对象的第二个大特性是『抽象』,咱现在先不说。

先说继承吧,比如这里有一个扩充的 Dog:

import static java.lang.System.out;

class WildDog extends Dog {
void bite(Doge other) { out.println("Dog "+this.name+" bites "+other.name); }
}

野狗也是一种狗,注意,它「是」,一种狗,这意味着所有可以提供一个狗的地方,也都能接受野狗。

野狗是狗的超集,因为它可以上演狗咬狗的闹剧(当然,因为野狗也是狗而且 bite 接受的是 (Dog),野狗也可以咬同类)。

在 class WildDog 里面我们称 Dog 为子类(child class) 或者子类型(subtype)
Dog 则叫亲类(parent class) 或者父类、超类,因为 Dog 的成员可以被 WildDog 里的 super 关键字引用。

放到工程实践里来,继承给了我们更加细化一个类的方法,由超类提供一些更大范畴的东西(比如狗是动物、黄种人是人),再由它的子类加以细化特化,就形成了一个更容易复用代码、定义的编程方法。

抽象呢,在有了继承以后就很好理解了。
上面的 class Logger 例子,是基于 java.lang.System.out 的,它是 java.io.PrintStream 的实例 (终端工具 $ javap ClassID 可以查看它们的成员定义)
可是现在甲方又有一个要求,要兼容另一个支持 void appendln(String line); 的…… JiaFangStream 实例,怎么办?
我们 Logger#printHead 的核心算法是『输出一行 [head] text』。
这个动词,可以是很抽象的。细化一点,我们说它接受一个 String,没有返回值的子程序,或者说函数。
函数可能有很多参数,以及一个返回值,或者 void

abstract class Logger {
protected abstract void printLine(String line);
protected void printHead(String head, String text) { pintLine("["+text+"] "+text); }
class StandardLogger {
StandardLogger(PrintStream outs) {/**/}
@Override protected void printLine(String line) { outs.println(line); }
}