duangsuse::Echo
这次就有一些我最想先弄的东西: + 程序设计语言::Closure、Pattern Matching、Stream、Generators #pl #cs + 程序设计语言类型::常见名词 + 数据库::关系代数 #db + Java 的二进制流读写器 #bin + Java 的 Android android.content.SharedPreferences 代理库 Prefer + {软件架构, Android}::编写 Android ShutdownService + Kotlin::简单的…
这周份的 duangsuse::Echo 技术日常!包括计算机科学、关系代数、程序设计语言理论相关内容!
= 程序设计语言::Closure、Pattern Matching、Stream、Generators #PL #CS
Closure[wiki]: aka. Proc(Ruby)、闭包、Block、Chunk(Lua, 不完全是, Lua 里 Closure 等价的概念是自动内存管理和存储层的 UpValue 和 Proto,当然得配成一对才是闭包, Chunk 说的实际上是『一段完整的程序』)、Lambda(Lisp, Scheme, Haskell, Scala, etc.)、匿名函数(JavaScript, 虽然 ES6 也是有”箭头函数“的)
Python 和 ES6 的 decorators,也是基于他们的高阶函数支持而设计的。
代码块实际上是『上下文代码的一部分』,其概念源于 Lambda calculus — 函数可以返回函数,而『函数作为值』本身的意思,就是函数可以”独立“于调用栈的存储空间而存在,这意味着函数要知道自己定义时的作用域以保证再次执行时不会出 undefined reference 错 — 它可以『携带』自己所需要的定义离开一层函数调用栈帧,这就是 Lexical Scoping
非常明显的行为是,返回的 λy.... 里依然可以访问到 λx.... 里的变量 x
可是有人要写这样的程序:比如把
但是很不幸,函数式编程和面向对象混合的多范式成了主流;随处用高阶函数 Higher-Order-Function 和指定 receiver 的方法;于是这种辣鸡代码写起来不再有难度:
在 ES6 里支持模式识别的一种子集:
Destructuring assignment 解构赋值
我只知道,ES6 支持:
+ List pattern like
+
详情 MDN
Scala 的 Pattern Matching 详情这里
(比 ES6 的牛逼多了,因为 ES6 的只是结构赋值、Scala 的不仅可以解构赋值还可以判定)
因为上面定义了:Maybe a 可能是 Just a 或者 Nothing,它是 a 的 Sum type (tagged union)
Stream:
流式 API,充分利用对象自治性,是面向对象架构必须有的东西
= 程序设计语言::Closure、Pattern Matching、Stream、Generators #PL #CS
Closure[wiki]: aka. Proc(Ruby)、闭包、Block、Chunk(Lua, 不完全是, Lua 里 Closure 等价的概念是自动内存管理和存储层的 UpValue 和 Proto,当然得配成一对才是闭包, Chunk 说的实际上是『一段完整的程序』)、Lambda(Lisp, Scheme, Haskell, Scala, etc.)、匿名函数(JavaScript, 虽然 ES6 也是有”箭头函数“的)
Python 和 ES6 的 decorators,也是基于他们的高阶函数支持而设计的。
代码块实际上是『上下文代码的一部分』,其概念源于 Lambda calculus — 函数可以返回函数,而『函数作为值』本身的意思,就是函数可以”独立“于调用栈的存储空间而存在,这意味着函数要知道自己定义时的作用域以保证再次执行时不会出 undefined reference 错 — 它可以『携带』自己所需要的定义离开一层函数调用栈帧,这就是 Lexical Scoping
(lambda x.
lambda y. x) 1 ; res0=λy. 1(res0 2) ; 1非常明显的行为是,返回的 λy.... 里依然可以访问到 λx.... 里的变量 x
def foo()而以前我们直接用 Java 的 Collections framework 会这么写(虽然这里好像都是在用 [Array...):
a = 1 # 闭包里包含了这个局部变量,如果 lambda 被当成值返回,这个变量将会被保存
[1,2,3].map { |x| x + a } #=> [2,3,4]
end
public static final void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
非常愚蠢(但还是比汇编和 while 循环好多了)于是就有了 forEach,正如后来的 tryWithResource 和 Autoboxing 一样public static final void main(String... args) {
for (String s : args) System.out.println(s);
}
大括号保不保留就是一个见仁见智的问题,支持者认为不保留好看,不支持的人觉得重构麻烦容易出错,当然控制流跳转的 return 怎么用也是一样的见仁见智问题。可是有人要写这样的程序:比如把
int[] 变成 boolean[], 这要求 forEach 做它做不到的事情:先预备好一个同样维度的数组;知道当前在哪次循环;然后下标赋值目标数组,也就是说得同时读写两个数组,都需要下标public static final void main(String[] args) {
boolean[] args_bs = new boolean[args.length];
Predicate<String> predicate = s -> s.length > 10;
for (int i = 0; i < args.length; i++) {
args_bs[i] = predicate.test(args[i]);
}
}
于是又有了 init; p; op 的 for statement....但是很不幸,函数式编程和面向对象混合的多范式成了主流;随处用高阶函数 Higher-Order-Function 和指定 receiver 的方法;于是这种辣鸡代码写起来不再有难度:
fun profiteer(giftList: String)Pattern Matching[wiki]:
= fun output(writer: PrintStream)
= giftList
.split("\n")
.map(::Gift) // Constructor, (String) -> Gift
.map { it.mapIncreasePrice(10.dollars()) }
.forEach(writer::println)
在 ES6 里支持模式识别的一种子集:
Destructuring assignment 解构赋值
我只知道,ES6 支持:
+ List pattern like
[a, b = 2, c], [head, ...tail]
+ Object pattern { length: 2 = -1 }
+ 当然上面的 Object destruct 也可以用 ES6 的同名属性变量语法糖+
let { length } = [1] 里的 {length} 说的其实是 {length:length}, 给它指定了默认的键:length详情 MDN
Scala 的 Pattern Matching 详情这里
(比 ES6 的牛逼多了,因为 ES6 的只是结构赋值、Scala 的不仅可以解构赋值还可以判定)
def escape(s: String) = s match {
case 'q' :: xs => "\\q" ++ escape(xs);
case 'x' :: xs => "\\x" ++ escape(xs);
case x :: xs => x ++ escape(xs);
}
这种的 ES6 的解构赋值就做不到,不过也是因为模式匹配搞基一点的原因,所以会有诸如 Pattern exhaustiveness 之类的问题(比如 Haskell 里的 Maybe)data Maybe a = Just a | Nothing deriving (Eq, Show)可是
class FromMaybe a where
fromMaybe :: Maybe a -> a
instance FromMaybe String where
fromMaybe (Just s) = s
instance FromMaybe String... 会报错,因为 (
fromMaybe
:: Maybe a -> a) 只定义了解构
(Just ...) 这个数据构造器的解构器,到 Nothing 这个 case 就傻眼了(因为上面定义了:Maybe a 可能是 Just a 或者 Nothing,它是 a 的 Sum type (tagged union)
data Maybe a where实际上
Just :: a -> Maybe a
Nothing :: Maybe a
Sum type is a data structure used to hold a value that could take on several different, but fixed, types.
FromMaybe 这个用来进行 operator overloading 的 Typeclass 是完全设计错误的 ,它的 (fromMaybe
:: Maybe a -> a) 类型签名真的就是很愚蠢啊(除非有默认值,否则
(Maybe a) -> a 就是完全没有意义的事情)!Stream:
流式 API,充分利用对象自治性,是面向对象架构必须有的东西
val preference by lazy { Prefer.from(UserPreference::class) }
preference
.beginTx()
.setUserName("duangsuse")
.setIcon(File("duangsuse.png"))
.setAge(preference.age)
.delete("oldUserName")
.put("newUserNameNth", preference.read("newUserNameNth").or(0).inc())
.commit()
preference.userName //=> "duangsuse"
preference.length //=> 5
preference.has("user_name") //=> true
Generators[wiki]: aka. Coroutine(Lua), Fiber(in Ruby), Goroutine(Go), Suspend function/Coroutine(Kotlin), Generators(Python, JavaScript ES6, CSharp), Continuation(Scheme, Continuation 是一个抽象的程序执行状态,比 Coroutine 概念大一些)
duangsuse::Echo
啊嗨! java.lang.Deprecated 是什么鬼类型…
Kotlin:
交叉 inline 哦,双重 inline 那就叠在一起好了,免得 return 不到地方
交叉 inline 哦,双重 inline 那就叠在一起好了,免得 return 不到地方
inline infix fun <A, B, C> ((A) -> B).andThen(crossinline op: (B) -> C) = { x: A -> op(invoke(x)) }
REPL 里好像有问题,就infix fun <A, B, C> ((A) -> B).andThen(op: (B) -> C) = { x: A -> op(invoke(x)) }
inline fun <T> eq(me: T): (T) -> Boolean = { other -> me == other }
fun Class<*>.static() = object { public operator fun get(name: String): Field = this@static.getDeclaredField(name) }
fun assertSignedMinMax<reified T>(klass: Class<T>)
= fun assertLen(len: Int)
= (klass)
😶 没力气写了...println("forall x in Int. x in [2^32, 2^32-1]") (
duangsuse::Echo
这周份的 duangsuse::Echo 技术日常!包括计算机科学、关系代数、程序设计语言理论相关内容! = 程序设计语言::Closure、Pattern Matching、Stream、Generators #PL #CS Closure[wiki]: aka. Proc(Ruby)、闭包、Block、Chunk(Lua, 不完全是, Lua 里 Closure 等价的概念是自动内存管理和存储层的 UpValue 和 Proto,当然得配成一对才是闭包, Chunk 说的实际上是『一段完整的程序』)、Lambda(Lisp…
import static java.lang.System.out;如果使用 Coroutine,就可以写更优雅的 Clock 了
import java.util.Iterator;
class Clock implements Iterable<Boolean> {
private boolean state;
public Clock(boolean initialState) {state = initialState;}
public Clock() {this(false);}
class ClockIterator implements Iterator<Boolean> {
@Override public boolean hasNext() {return true;}
@Override public Boolean next() { state = !state; return state; }
}
@Override public Iterator<Boolean> iterator() {return new ClockIterator();}
}
public final class ClockMain {
public static void main(String... args) throws InterruptedException {
Clock clock = new Clock();
for (boolean b : clock) {
out.print(b ? "🕐Tick" : "🕒Tock");
Thread.sleep(500);
out.write(0x1b); out.print("[6D"); // https://en.wikipedia.org/wiki/ANSI_escape_code#DL
}
}
}
,再比如,如果使用控制结构:
= 程序设计语言类型::常见名词
= 数据库::关系代数 #DB
duangsuse::Echo
#Java #code 里面有个 inner class
当然,你也可以使用 Qualified class instance creation,只是因为 Java 有 inner class 自动绑定上父域类的状态而已
@Override public Iterator<Boolean> iterator() {return new Clock().new ClockIterator();}
duangsuse::Echo
import static java.lang.System.out; import java.util.Iterator; class Clock implements Iterable<Boolean> { private boolean state; public Clock(boolean initialState) {state = initialState;} public Clock() {this(false);} class ClockIterator implements…
然后我们还可以去写一个更 precious 的 Clock,它不仅会 Tick tock 还能记录时间,它被称为:TimedClock
也很简单,代码里几乎不需要什么修改
(这里明显不是教你怎么用 Generator,因为 yield 太简单了很多人章口就莱,是教你们怎么用 Iterator + switch 在 Java8 里手动写基于状态 🐔 的 Generator)
也很简单,代码里几乎不需要什么修改
(这里明显不是教你怎么用 Generator,因为 yield 太简单了很多人章口就莱,是教你们怎么用 Iterator + switch 在 Java8 里手动写基于状态 🐔 的 Generator)
duangsuse::Echo
也相当鬼畜,不过还没有教到使用 switch 进行自由控制流跳转的局面,待会会为大家做现场的表演~
修一下 bug、增加 Tick Thock,下面有更加 excited 的 clock。
duangsuse::Echo
修一下 bug、增加 Tick Thock,下面有更加 excited 的 clock。
最后我们还有一个最搞基的 Stream:
它的逻辑类似:
它的逻辑类似:
function *excitedGenerator() {
yield 3;
yield 2;
yield 1;
// Go!
for (let x of [1,2,3]) yield (Math.trunc(Math.random() * 100) * x)
let clock = new TimedClock();
yield *clock;
}
我们要使用裸 Java,不使用编译器的 suspend function 支持自己手写出来这种 Iterable!
duangsuse::Echo
然后我们还可以去写一个更 precious 的 Clock,它不仅会 Tick tock 还能记录时间,它被称为:TimedClock 也很简单,代码里几乎不需要什么修改 (这里明显不是教你怎么用 Generator,因为 yield 太简单了很多人章口就莱,是教你们怎么用 Iterator + switch 在 Java8 里手动写基于状态 🐔 的 Generator)
那么看来,手写基于状态 🐔 的 Generator 好不好用啊?
准确的说,是”很“不好用...
推荐不要使用,就用 ES6、Kotlin 的 Generator 好了,Generator 还有 async 函数,都是现在不可或缺的语言特性呢。
async 函数,就是说以顺序编程的思路写基于异步/回调的程序逻辑,所谓这么『同步地』写,正是基于可随时挂起继续的协程
#CS
准确的说,是”很“不好用...
推荐不要使用,就用 ES6、Kotlin 的 Generator 好了,Generator 还有 async 函数,都是现在不可或缺的语言特性呢。
async 函数,就是说以顺序编程的思路写基于异步/回调的程序逻辑,所谓这么『同步地』写,正是基于可随时挂起继续的协程
async () => {
let f = await readFile("foo.ext");
let pst = await parseFile(f);
await showUI(pst);
}
语法糖后面藏着的其实是随时可以挂起的 async() =>readFile("foo.ext").then(
(f) => parseFile(f).then (
(pst) => showUI(pst);
);
);
我执行一个异步任务,挂起等待,等待异步任务回调我这个可随时暂停恢复执行的 Generator,然后再来进行下一步操作,等价这么写嵌套的 Promise then
当然,协程也是分对称非对称的,不过都主要是理论,对称协程可以随便 yield 控制权,非对称只有 creator 可以把执行权交回子协程,非对称协程可以实现对称协程。#CS
duangsuse::Echo
那么看来,手写基于状态 🐔 的 Generator 好不好用啊? 准确的说,是”很“不好用... 推荐不要使用,就用 ES6、Kotlin 的 Generator 好了,Generator 还有 async 函数,都是现在不可或缺的语言特性呢。 async 函数,就是说以顺序编程的思路写基于异步/回调的程序逻辑,所谓这么『同步地』写,正是基于可随时挂起继续的协程 async () => { let f = await readFile("foo.ext"); let pst = await parseFile(f);…
GitHub
duangsuse/Essay-Java8-CST-Based-Generators
Control structure / java.util.Iterator / class instance private state based suspend functions just like C# yield state machine - duangsuse/Essay-Java8-CST-Based-Generators
duangsuse::Echo
import static java.lang.System.out; import java.util.Iterator; class Clock implements Iterable<Boolean> { private boolean state; public Clock(boolean initialState) {state = initialState;} public Clock() {this(false);} class ClockIterator implements…
= 程序设计语言类型::常见名词 #PL #PLT
🤔 有的时候看见诸如王垠这样的人的博客都会感觉好大佬的样子呢。
什么 soundness、completeness、type checker、intersection type、product type... 满嘴是我们这些菜鸡听不懂的 dalao 词汇,一瞬瞎眼膜拜。
其实你只是不明觉厉,这些都是类似”加盐“一样半俗半释的词:比如 Product Type,它其实也没有什么特殊的,只不过说某种 type 是其他一些 type 的融合罢了,看完下面的文字你很快就会明白这些常用名词的含义
要说真正困难的东西,那当然是线性代数莫属喽,给你每个名词的解释你都不一定能弄懂。
为了帮助你们学习这些程序语言类型领域的名词,首先我们得对程序设计语言的抽象语义、解释器、类型检查等概念有个基础的认识。
本教程主要面向刚入门的萌新快速上手,不会提及某些搞基的函数式语言诸如 Scala / Haskell / Agda 的搞基类型特性,比如 Higher-ranked polymorphism, Existential types, Coinducative data types
下面是本期学习到的名词,看起来好高大上呢。
+ [for type checkers] Soundness and completeness
+ Duck/Statically typed, explicitly(implicitly) typed, weakly/strongly typed
+ Type inference / type inferer
+ Types and values
+ Type erasure [Parametric polymorphism]
+ Type constructor
+ Type conversion
+ (Homogenus) Product type
+ Sum type
+ Subtyping
+ Paramized types (Parametric polymorphism)
+ Zero size types (aka. Unit types)
+ Empty types / Bottom type
+ Traits
+ Dependent type
== 什么是类型
不得不引用某 Haskell Values/Types 理论的简易入门了。
类型是什么呢?如果讨论上下文是 C、Java、Kotlin、Dart 这类简单的语言,类型可以被视为集合,某一个位置所有可能出现的值(value)的集合(有时候也可以被说成阶,但其实还是集合方便理解)
Java 的 boolean 就是
比如,有一个函数
这样就给我们的操作(比如二元运算、值传递、赋值语句等)定义了一个限制 —
类型系统的本意关于模块化、安全和优化 — 安全和优化是共生的,因为 Java 是安全的语言,不能让程序因为索引越界这种弱智问题导致更坏的结果,所以 Java 要做很多检查,类型检查,无论编译时或是运行时都一样,而把运行时的开销提升到编译期显然可以使得开销更小,而利用类型系统共生的多态(polymorphism)特性,诸如子类型多态、函数重载、类型转换多态、参数化类型等,可以大大提升程序的抽象性,使得软件工程更方便易读易维护。
比如 Java 的
Java 的 String 虽然是一种 product type,但是也可以认为是一个集合:
=== 类型架构器
类型构造器就是接受类型,返回类型的玩意
Kotlin 里的
此外,Java 5 引入的 Generics 也是一种类型构造器
== first-class 是什么意思
在程序设计语言理论的上下文中,说某个概念是 ”first-class“ 的(有的人也是说”作为值“,其实也都差不多,毕竟值也基本都是 first-class)
+ 可以被作为『函数』(子程序)的参数或者返回值
+ 可以被存储到诸如本地变量这样的容器里
不然的话,就被称为非 first-class (non first class)
== 组合和类型
== Type constructor
A type constructor is a feature of a typed formal language that builds new types from old ones. Basic types are considered to be built using nullary type constructors. Some type constructors take another type as an argument, e.g., the constructors for product types, function types, power types and list types. New types can be defined by recursively composing type constructors.
For example, simply typed lambda calculus can be seen as a language with a single type constructor—the function type constructor (→). Product types can generally be considered "built-in" in typed lambda calculi via currying.
🤔 有的时候看见诸如王垠这样的人的博客都会感觉好大佬的样子呢。
什么 soundness、completeness、type checker、intersection type、product type... 满嘴是我们这些菜鸡听不懂的 dalao 词汇,一瞬瞎眼膜拜。
其实你只是不明觉厉,这些都是类似”加盐“一样半俗半释的词:比如 Product Type,它其实也没有什么特殊的,只不过说某种 type 是其他一些 type 的融合罢了,看完下面的文字你很快就会明白这些常用名词的含义
要说真正困难的东西,那当然是线性代数莫属喽,给你每个名词的解释你都不一定能弄懂。
为了帮助你们学习这些程序语言类型领域的名词,首先我们得对程序设计语言的抽象语义、解释器、类型检查等概念有个基础的认识。
本教程主要面向刚入门的萌新快速上手,不会提及某些搞基的函数式语言诸如 Scala / Haskell / Agda 的搞基类型特性,比如 Higher-ranked polymorphism, Existential types, Coinducative data types
下面是本期学习到的名词,看起来好高大上呢。
+ [for type checkers] Soundness and completeness
+ Duck/Statically typed, explicitly(implicitly) typed, weakly/strongly typed
+ Type inference / type inferer
+ Types and values
+ Type erasure [Parametric polymorphism]
+ Type constructor
+ Type conversion
+ (Homogenus) Product type
+ Sum type
+ Subtyping
+ Paramized types (Parametric polymorphism)
+ Zero size types (aka. Unit types)
+ Empty types / Bottom type
+ Traits
+ Dependent type
== 什么是类型
不得不引用某 Haskell Values/Types 理论的简易入门了。
类型是什么呢?如果讨论上下文是 C、Java、Kotlin、Dart 这类简单的语言,类型可以被视为集合,某一个位置所有可能出现的值(value)的集合(有时候也可以被说成阶,但其实还是集合方便理解)
Java 的 boolean 就是
true 或者 false
boolean 是类型,true 和 false 是值比如,有一个函数
abstract void acceptBoolean(boolean b);
实际上是说它”接受所有“ boolean 集合里的值 — true、false这样就给我们的操作(比如二元运算、值传递、赋值语句等)定义了一个限制 —
boolean 类型的参数只能被传入 boolean 类型的东西(变量、常量...)、boolean 类型的本地变量只能被赋值为 boolean....类型系统的本意关于模块化、安全和优化 — 安全和优化是共生的,因为 Java 是安全的语言,不能让程序因为索引越界这种弱智问题导致更坏的结果,所以 Java 要做很多检查,类型检查,无论编译时或是运行时都一样,而把运行时的开销提升到编译期显然可以使得开销更小,而利用类型系统共生的多态(polymorphism)特性,诸如子类型多态、函数重载、类型转换多态、参数化类型等,可以大大提升程序的抽象性,使得软件工程更方便易读易维护。
比如 Java 的
int 就是一些数字,从 -Integer.MAX_VALUE 数到 Integer.MAX_VALUE...Java 的 String 虽然是一种 product type,但是也可以认为是一个集合:
"a" / "ab" / "ac" / "duangsuse" ....=== 类型架构器
类型构造器就是接受类型,返回类型的玩意
Kotlin 里的
? 是一种类型构造器,比如:Int? 里的 ? 接受一个 kotlin.Int 类型,返回一个 kotlin.Int? 类型(Int? 是 Int 的父类型,因为它可以是 null,或者说 Int? 是 Int 和 Nothing? 的 Union type,在类型层面上是的)此外,Java 5 引入的 Generics 也是一种类型构造器
java.util.ArrayList<T> 接受一个 T 类型,返回一个 ArrayList<T> 类型java.util.function.Consumer<T> 接受一个 T 类型,返回一个 Consumer<T> 类型== first-class 是什么意思
在程序设计语言理论的上下文中,说某个概念是 ”first-class“ 的(有的人也是说”作为值“,其实也都差不多,毕竟值也基本都是 first-class)
+ 可以被作为『函数』(子程序)的参数或者返回值
+ 可以被存储到诸如本地变量这样的容器里
不然的话,就被称为非 first-class (non first class)
== 组合和类型
— Haskell这是利用
inc :: Int -> Int
inc n = n +1
(+) 操作符和两个 Int 构建的一个计算,(+) 的类型是:(+) :: Int -> Int -> Int给它两个 Int,然后它会返回一个 Int — 简单的 Int 二元运算
== Type constructor
A type constructor is a feature of a typed formal language that builds new types from old ones. Basic types are considered to be built using nullary type constructors. Some type constructors take another type as an argument, e.g., the constructors for product types, function types, power types and list types. New types can be defined by recursively composing type constructors.
For example, simply typed lambda calculus can be seen as a language with a single type constructor—the function type constructor (→). Product types can generally be considered "built-in" in typed lambda calculi via currying.