duangsuse::Echo
719 subscribers
4.28K photos
130 videos
583 files
6.49K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
duangsuse::Echo
刚才阅读代码加强理解的时候忽然发现不对,这个 chianr1 怎么和 chainl1 是一样的,对着冰封的博客,发现我写错了...
#fix #haskell #fp #cs #wip #recommended #saved 这个问题,暂时就说到这里了

以后有机会我会跟冰封哥说... 看看他知不知道为什么
先做更有价值的事情

我也真是醉了,看了 #Monad Parser 是很迷啊
留影纪念,chainr1:rest 和 chainl1:rest 的区别只在 rhs 是 scan combine 自己还是 scan {+ 1} 这种
BinOps
1.4 MB
#tool 计算器最终版(
BinOps.hs
7.8 KB
duangsuse::Echo
BinOps
[DuangSUSE@duangsuse]~/Projects% ./BinOps
Sigma :: + - * / ** mod unm logN sin cos tan 0xFF_FF 2.1
1+2+3
Σ We got: 1+2+3
= Just ((1.0 + 2.0) + 3.0)
= 6.0
2**2 ** 3
Σ We got: 2**2 ** 3
= Just (2.0 ** (2.0 ** 3.0))
= 256.0
unm 2 + 43 ** 4 + 2
Σ We got: unm 2 + 43 ** 4 + 2
= Just ((-2.0 + (43.0 ** 4.0)) + 2.0)
= 3418801.0
0xFF
Σ We got: 0xFF
= Just 255.0
= 255.0
0.5 * 10 * 100
Σ We got: 0.5 * 10 * 100
= Just ((0.5 * 10.0) * 100.0)
= 500.0
log2 10
Σ We got: log2 10
= Just log2 10.0
= 3.0
10 mod 3
Σ We got: 10 mod 3
= Just (10.0 mod 3.0)
= 1.0
10 mod 3 mod 1
Σ We got: 10 mod 3 mod 1
= Just (10.0 mod (3.0 mod 1.0))
= [E] Division by zero
sin 0.3333
Σ We got: sin 0.3333
= Just sin 0.3333
= 0.32716319804950605
duangsuse::Echo
绝望,看来写不了了,就学点 Haskell 吧。 选择一下 写个 JSON Parser,不过必须得把某 Monad 组合子 Parserc 框架抄写下来,这个是没有技术难度的... 扩展这个计算器,支持 ** 和 mod 运算,支持十六进制和运算符结合算了... 🙈
duangsuse 的打算,从现在就开始做:

Parser 写了不到一半,emitter 正在写,框架代码抄了正在研究是怎么工作的
1. Haskell 写 JSON 处理算法,还要把一个 Monad Parserc 框架的代码手动抄过来

1.5 抄!把某篇 Hindley-Milner 类型系统的推导算法教程里的 Haskell 代码抄下来!

2. 写 BinaryStreamIO

还要附带 Aapt 资源的 parser,因为找不到规范,直接抄 sdklite/aapt 的好了(炒鸡好看)
和 JVM / Dalvik 字节码处理框架,Yes

别人的巧克力重写了就是我做的巧克力(逃跑

3. 写 Java 8 的 TextCombinator 库,

还要附带 TrieTree、RangeMap、VersionizedMap、MultiMap 等算法
用来做 IDE 支持这样的工作

4. 写 Markdown 解析器

5. 练习 Qt 或者 Java Swing / AWT 的技术,反正就是 Desktop GUI 的技术...

6. 利用 TextCombinator 写一个 NaiveCat 的解释实现

NaiveCat 是简单版本的 Cat,后者比较详尽的定义已经在这里有几面了
NaiveCat 没有诸如 Coroutine、Lazy evaluation 这样的特性,算是半函数式半面向对象

配合新解析器框架刚刚好
duangsuse::Echo
[DuangSUSE@duangsuse]~/Projects% ./BinOps Sigma :: + - * / ** mod unm logN sin cos tan 0xFF_FF 2.1 1+2+3 Σ We got: 1+2+3 = Just ((1.0 + 2.0) + 3.0) = 6.0 2**2 ** 3 Σ We got: 2**2 ** 3 = Just (2.0 ** (2.0 ** 3.0)) = 256.0 unm 2 + 43 ** 4 + 2 Σ We got: unm…
有一个小细节: #pl #algorithm

提到 pretty,虽然我们可以把

Add
Rat 1
Rat 2

这样的树给安全地输出成 (1 + 2) 的形式,但是肯定还是有人嫌太长(括号根本不需要)

但是如果输出成 1 + 1 的形式呢,就会出现下面的问题

(2 + 1) * 2

本来是
Mul
Add
Rat 2
Rat 1
Rat 2

你这么一整,就成了
2 + 1 * 2
Add
Rat 2
Mul
Rat 1
Rat 2

语义不对。

有两种解决方案,一是对于每个二元子节点访问,dump 后再 parse 一遍,结果相同就返回无括号版本,否则返回有括号保险版
优点是肯定有效(而且不需要专门写解析器外的算法)
缺点... 我就不用说了,别说 Haskell 里那个 Text.ParserCombinator.ReadP Monad 解析组合子了,其他的非得再解析一遍,咸得🥚

还有一种方案可以处理这种问题(排除二元 / 一元在一起的坑爹情况,不过其实也都是一个道理,判断出要加括号的 case 加括号,不加的不用加)

要输出 (2 + 1) * 2 这个树,其实就是访问 Mul 节点的时候,判断一下子节点是否打破了运算符优先级

如果是正常情况,+ 的优先级没有 * 高,所以往往 * 是 + 的子节点,而不是上面这种情况

推广来说,就是发现自己左节点优先级没有自己高,就可以不带括号输出,相等则要看结合性情况(左结合右结合都要判左右手,判自己的就是左结合左手应该是自己、右结合右边应该是自己,否则就打破了结合性)

输出 (Mul (Add x y) y') 这种的,就给子节点加上括号再输出

"(" ++ dump x' ++ ") * " ++ dump y'

就不会有格式化错误的问题了


最后一段属于推销可以不看(

当然有没有第三种方法呢?档燃有啊!
就是使用 RangeMap 和 ReverseMap,在解析的时候就加上空格信息(当然也包括括号信息)喽!
然后保存这些信息,到时候如果要输出可以复用
https://github.com/996icu/996.ICU/blob/647be115cf640f7e0879321361abfbee4ac1f4b7/archived/licenses%5BWIP%5D/tools/gen-license-rs/src/main.rs
https://github.com/996icu/996.ICU/blob/647be115cf640f7e0879321361abfbee4ac1f4b7/archived/licenses%5BWIP%5D/tools/test-gen-license/src/test_go.rs

说起来,我差点以为 996.icu 是 Rust 写的呢... Rust 和 Go 也该学学了,虽然我连 C++ 都不太会...

说起来, #Rust 还有点可怜,996.icu 的支持者用 Rsut 创建了 Go Python Rust 三语的 tests,可是 Rust 版本的测试却没有
duangsuse::Echo
左结合: 总不可能这样来『兼容』嵌套的二元运算 add$2 = num "+" num add$3 = num "+" num "+" num add = add$2 | add$3 也不可能来这样 op = "+" | "-" | "*" | "/" bin = num { op num } 为啥解析的时就能创建好的结构,非得解析完了再去创建? 当然可以这样 bin = (num|bin) op num 就是左递归,可是就不方便 然后介绍了一个 chainr1 和 chai…
所以 RankNTypes 为啥要用 forall 呢? #haskell #cs #pl #plt

我们的类型系统,主要还是通过类型检查器『Type Checker』影响到我们编程的

{-# LANGUAGE RankNTypes #-}
foo :: (forall a. a -> a) -> (Char, Bool)
foo f = (f 'c', f True)

∀forall,就是说对于所有可能的类型选项,都有 ... 成立

比如 (id :: forall a. a -> a)
a 类型是 Int 的时候成立,
String 的时候也成立

class Show a where
showsPrec :: Int -> a -> ShowS
show :: a -> String
showList :: [a] -> ShowS
{-# MINIMAL showsPrec | show #-}

show :: forall a. Show a => a -> String
再比如 show, a 是 Int 时有 show :: Int -> String、是 Bool 时也有 show :: Bool -> String
只要前提条件 『a 类型有一个 Show 的实例 instance』成立就有 show :: a -> String

这段代码里,foo 的类型,如果不使用 RankNTypes,这么表示(虽然不能用,因为后面的程序逻辑问题)

foo :: forall a. (a -> a) -> (Char, Bool)

看到没有?这个 forall 全称限定是 foo :: 里面的
如果我们要这么写:

foo f = (f 'c', f True)

上面的类型签名是说,这个 foo 是一个接收函数 (a -> a) 返回元组 (Char, Bool) 的函数,这里 a 只有一个(要么然是 Char 要么然是 Bool 要么然是...)
所以,Type checker 就报错了,因为它按照基本法🐸以为 f :: a -> a 在第一次 beta-reduction (f True) 的时候类型已经确定是 Bool 了,不知也可以是 Char

这里 RankN 的 N 是 1,不变态(皮一下,不是我说的

Prelude> foo = (\f -> (f True, f 'a'))

<interactive>:2:25: error:
Couldn't match expected type ‘Bool’ with actual type ‘[Char]’
• In the first argument of ‘f’, namely ‘"abc"’

如果我们使用 Rank N Polymorphism 呢?

foo :: (forall a. a -> a) -> (Char, Bool)

这里 RankN 的 N 是 2

Prelude> foo = (\f -> (f True, f "abc")) :: (forall a. a -> a) -> (Bool, String)
Prelude> foo id
(True,"abc")

我们发现,现在这个 a 可以『同时』是 Char 和 Bool 了
因为我们说『foo 的输入是 a -> a,而这个 a 是这个函数它局部的限制,不是 foo 里的 a 全都得是某个类型』

参考:范畴论完全装逼手册

没错,写 Haskell、Agda、Scala 就单单是为了装逼... 🤪

复制过来方便对比,从侧面就能看到其实我也不是很擅长完全理解再自己编出示例程序...
rank2 :: forall b c . b -> c -> (forall a. a -> a) -> (b, c)
rank2 b c f = (f b, f c)

rank2 True 'a' id
-- (True, 'a')

用 Scala 写,所以 JVM 还是很 FP 的?(....
def rank2[B, C](b: B, c: C)(fnk: Id ~> Id): (B, C) =
(fnk(b), fnk(c))
rank2(true, 'a')(FunctionK.id[Id])
#distributed #game #net CDN 同意,多 DC 可能反而不方便...
Forwarded from Rachel 碎碎念 (IFTTT)
真的 不是很明白为什么国内的游戏都有几十上百个区 而且区与区之间数据不互通…
感觉这种设计极其落后而且反人类
9102 年了还不普及 CDN 和多数据中心设计…— Rachel Miracle. (@tangrui003) April 28, 2019
有一些分区是因为国内没有 Google Play 的缘故
duangsuse::Echo
有一些分区是因为国内没有 Google Play 的缘故
emmmm
#coolapk 这牛批了老铁... 🌚 #Low
Forwarded from neko1
这谁顶得住
duangsuse::Echo
这谁顶得住
This media is not supported in your browser
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
这酷安简直有毒啊