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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
#Mathematics #PL #Math #learn

+ 数学上的分段函数

还是看 PDF 吧。TeX 命令也可以贴不过我懒得贴了(因为我想找在线的即时预览编辑器,没找到能用的 hhhh

https://cn.overleaf.com/ 慢死了

116 面 e6. Haskell. 等价,虽然我不是特别熟悉 Haskell 所以有余赘

p(h) | (h >= 0) = 7 * h
| (h <= 40) = 7 * h
| h > 40 = 10.5 * h - 140


或者我们可以更 less-boilerplate 一些,利用 Haskell 的 range

p h
| elem h [-1/0..40] = 7 * h
| h > 40 = 10.5 * h - 140


好吧,这个不会 terminate,因为我用的是 -Infinity... 而 Haskell 不知道我到底想说啥... 因为我也不咋会 Guard pattern

main = print $ p <$> [0..300] 然后至于数据画函数图像嘛可以随便找个软件比如 LibreOffice 什么的,KDE 也有转们的软件,要不然 Kotlin JavaAWT JPanel 也可以。

让我们再看看 Haskell 里的 Guard pattern
是类似的。不过这里 Haskell 的分布函数有个 branch exhaustivness check 的问题,比如 Fib 函数

fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

main = print $ fib 1


但这个 Guard pattern 版本

fib :: Int -> Int

fib n | n == 1 = 1
| n == 2 = 2
| otherwise = (fib n - 1) + (fib n - 2)

main = print $ fib 0


不 total(完全)(比如,输入 -1 就没有值),不 check。(咦?怎么能过?不 sound?)(之前 GHCi 过不了就是)

那么一定要用就可以上 undefined

+ 啥是 tailrec #Haskell #functional

首先啥是递归

Y = λf. (λx. f (x x)) (λx. f (x x))
(Y Y)

我们先来进行 β - 归约... 算了看过程

首先我们 f (x x) [ f := Y, x := (λx. f (x x)) ] 看不懂算了,因为数学的东西就是为了形式化,不易读的... 所以不数学算了(

(λx. f (x x)) (λx. f (x x)) where f = y 被替换为 (λx. Y (x x)) (λx. Y (x x))
然后接着展开... 唉头大,总之,类似这样就可以了,学个一半然后自己再学也没什么

(λf. (f f))
(λself. (self self))


首先 apply
(λself.

... 到
(lambda f.
(λself. (self self))



(λself. (self self))

apply... (self self) where self = (λself. (self self))

((λself. (self self))
(λself. (self self)))

又是它。无限循环。infinity recursion。结束分析....

然后看看这个 ES6 #JavaScript 的 tco 优化器,汲取灵感 <del>所以 ES6 还是很 functional 的</del>

function tco(fun) {
var value = null, active = false, accumlated = [];
return function accumlator() {
accumlated.push(arguments);
if (!active && (active = true)) { // 是的,我利用 && 非短路语义压行了
while (accumlated.length != 0) value = fun.apply(this, accumlated.shift());
active = false; return value;
}}} // 是的,Sexp 系写多了的结果...

sum = tco((x, y) => (y > 0) ? sum(x + 1, y - 1) : x);

console.log(sum(1, 100)) // 101


然后我们看看这个伪代码例子

type <A : Comparable<in A>> binarySearch : |A[]| |A| |Range| Int

binarySearch xs o <srch = xs.indexRange> = |>
let index = srch.mid, guess = xs[index] in when
| srch.len zero -> nil
| guess is o -> index
| guess > o -> tailrec(srch.a..srch.mid.sub1)
| guess < o -> tailrec(srch.mid.add1..srch.b)


tco 就是尾调用优化,如果一个函数的最后一步是调用自身或者兄弟函数(这个 case 目前请无视)就可以进行尾调用优化
这样调用栈帧就可以不保存,就不会 ~~上~~ 栈爆 ~~Stack Overflow~~ 了
其实我们发现这种递归可以优化为循环的(试试用循环 + 变量解决它),所以 tco 允许我们用递归的方式写循环

+ 过程和结果。副作用和返回值

有的时候我们更注重过程而不是结果,比如... 比如... (突然害羞)(迫真)生活中例子很多

比如....

puts "Hello, world!" #=> nil

class Foo; end

macro_rules! foo {
() => { "foo" };
};

`

nil 我们要你何用?
() 我们要你何用?

我们要的是
puts 调用产生的副作用,向 STDOUT 写出一行你好世界
我们要的是
class Foo 的副作用,定义一个 Foo 类赋值到 Foo 常量上
我们要的是
macro_rules! 宏的副作用,它把一个用户定义的宏注册到系统里面去以便使用

副作用在很多语言里都是 invisible 的,只有返回值和异常什么的可以在抽象函数调用之间传递
这也一般无可厚非,因为很多时候我们不要返回值只需要副作用而已,他们两个还是很不一样的

不过 Haskell 这完全 pure 的语言里面有 IO 类型,不过 @ice1000 都说他啥时候还觉得 Haskell 的 IO 不好理解我也不敢随便说话了

纯函数就是没有副作用的函数,一般数学函数都属于此类,纯函数不是什么不用
printf 也不是什么不用局部变量,它是说

+ 函数本身运行稳定可预期
+ 函数的运行不对外部环境产生影响
+ 函数的数据流全是显示的,就是说函数与外界环境交换信息只能使用它的参数(包括
this)和它的返回值

纯函数的好处是
+ 无状态,无需考虑线程安全
+ 纯函数的组合还是纯函数
+ 相同参数永远相同结果,可以缓存计算结果、延迟求值、改变求值顺序、改变求值环境、多次求值也可以随意

当然别处还有更严谨的定义,不过我不纠结这些就是了...

+ 扫描到树状图以及输出(挂起中,因为... 还有事...)

... 因为 UNIX 的 fs 文件系统都是比较方便的吧... 我们拿这个做例子快点讲了好办事

Haskell. 我们先来看看我们的需要的 API 抽象

``
import System.Environment
import System.Directory
import System.IO

lsdir :: FilePath -> IO [FilePath]
lsdir = listDirectory
fexists :: FilePath -> IO Bool
fexists = doesFileExist

data FTree = FTree [FTree] | Atom FilePath deriving (Eq, Read)
ftree :: FilePath -> FTree

instance Show FTree where
show FTree fs = show fs
show Atom fp = show fp

ftree = undefined

首先我们需要一个 API 来拿到文件夹子树


listDirectory "." >>= print

然后我们需要一个 API 判断『对象(路径表示的)』是文件还是目录(里面还有文件)


doesFileExist "/proc/cmdline" >>= print

`OK. 那么我们来实现 `ftree`