undefined设计方案(函数式编程5の恼人的undefined)(1)

来看看〈是的! 不是!〉中到底定义了什么?

let yes = f => y => f(); let no = x => f => f(); let when = c => c;

三个函数? 不! 三个“值”! 函数也是值! 因此 是个值, 也是个值,既然如此,可以用来替代仍借助于 JavaScript 的 、 吗? 可以的!yesnotruefalse

lambda 表示式就是值

这也给个机会,重新思考什么是值? 在多数程序语言中,值就是个定义好的符号,像是、、、、等,在 lambda 演算的世界中,lambda 表示式就是值,可以用 lambda 表示式来定义 、,这边的 、 就是实际的例子,进一步地 、、 也可以用 lambda 表示式来定义(这在后面的篇幅会谈到)。truefalse123truefalseyesno123

来试着不使用 、、 来完成 如何? 首先,List 的结构不用修改:?:truefalsemap(list(elems(1)(2)(3)))(elem => elem - 1)

let pair = l => r => f => f(l)(r); let left = p => p(l => _ => l); let right = p => p(_ => r => r); let nil = pair(undefined)(undefined); let con = h => t => pair(h)(t); let head = left; let tail = right;

接下来,看看,若有个代表着List,现在希望必须传回、而不是、,主要是看看首元素有没有定义,虽然可以写,不过来想想看,它该算是个值吗?let isEmpty = lt => head(lt) === undefined;ltisEmptyyesnotruefalseisEmptylet isEmpty = lt => head(lt) === undefined ? yes : no;undefined

定义 undef

undefined 是值吗? 或者只是个唯一的符号? 表示没有东西、也不是容器、没有对应的操作,什么也没有?undefined

若就 JavaScript 来说,将 当成一个值,因此,就目前来说可以利用这点,在目前的箭号函数表示中,将 当成是符号,让 JavaScript 代为判断 是 还是 :undefinedundefinedundefinedyesno

let is_undefined = n => n === undefined ? yes : no;

从 lambda 演算的角度来看, 会是个黑箱,是运算机器(这边就是 JavaScript 环境)的一部份,因此使用 、 就不是问题,这黑箱只要看看是不是 符号,写下 或 的 lambda 表示式就是了。is_undefined===?:undefinedyesno

实际上在目前的箭号符号表示方式中,有些地方虽然没有写出 ,然而隐含着使用了 这个符号,例如,有个函式 ,若以执行,就 JavaScript 环境来说, 就会是 ,也就是就 lambda 表示式来说,可以看成是 ,隐含地传入了 符号。undefinedundefinedf = x => x 1f()xundefinedf(undefined)undefined

如果直接使用 真的让你感到不舒服,那就来定义一个 好了:undefinedundef

let undef = (_ => _)();

就 lambda 演算角度来看, 像是个 lambda 表示式,如果以人力来运算,就是看看是不是 ,确定是不是未定值的表示式;如果使用 JavaScript 执行环境来运算, 也还是 ,最终,还是依然有个黑箱:(_ => _)()(_ => _)()undefundefined

let is_undef = n => n === undef ? yes : no;

重構

雖然黑箱依然存在,然而就目前來說,這可以讓事情簡單一些,最終的運算表示式中,也可以不出現 這個 JavaScript 中的元素,爽度應該會高一些。例如 List 的相關定義現在可以是:undefined

let pair = l => r => f => f(l)(r); let left = p => p(l => _ => l); let right = p => p(_ => r => r); let nil = pair(undef)(undef); let con = h => t => pair(h)(t); let head = left; let tail = right;

于是, 现在可以返回 、 了:isEmptyyesno

let isEmpty = l => is_undef(head(l));

接下来,可以实现几个简单的函数,像是 、 之类的:lensum

let len = l => when(isEmpty(l)) (_ => 0) (_ => 1 len(tail(l))); let sum = l => when(isEmpty(l)) (_ => 0) (_ => head(l) sum(tail(l)));

别忘了,由于 、、 实现了惰性, 接下来的两个值,必须是个函式,在这边略为排版了一下,看起来像是有了新的语言了。whenyesnowhen

在〈是的! 不是!〉也谈过, 只是增加一层语义,实际上什么也不做,也就是说,上例中的 直接写为 ,函式也可以正常运作,就上面两个函式来说,由于 名称上还算清楚,是可以这么做,然而若不是这类的名称,加上还是比较好的方式。whenwhen(isEmpty(l))isEmpty(l)isEmptywhen

接下来重构一下 等函数:list

let rcon = t => h => when(is_undef(h)) (_ => t) (_ => rcon(con(h)(t))); let rev = r => l => when(isEmpty(l)) (_ => r) (_ => rev(con(head(l))(r))(tail(l))); let reverse = l => rev(nil)(l); let elems = rcon(nil); let list = es => reverse(es());

来试试看:

let lt = list(elems(1)(2)(3)(4)); console.log(len(lt)); // 4 console.log(sum(lt)); // 10

实现一下 函数 :map

let map = l => f => when(isEmpty(l)) (_ => nil) (_ => con(f(head(l)))(map(tail(l))(f)));

如果有个辅助函数为 ,可以将List转为 JavaScript 阵列,那么底下会显示 [0, 1, 2]:array

let lt2 = map(list(elems(1)(2)(3)))(elem => elem - 1); console.log(array(lt2));

辅助用的函数与 lambda 演算没直接关系,代码如下:

function array(lt) { function arr(acc, l) { if(isEmpty(l) === yes) { return acc; } else { return arr(acc.concat([head(l)]), tail(l)); } } return arr([], lt); }

来试着像之前那样,将 全部使用箭号函数表示:map(list(elems(1)(2)(3)))(elem => elem - 1)

(f => (x => f(n => x(x)(n)))(x => f(n => x(x)(n))))(map => l => f => (l => is_undef((p => p(l => _ => l))(l)))(l)(_ => ((l => r => f => f(l)(r))((_ => _)())((_ => _)())))(_ => (h => t => (l => r => f => f(l)(r))(h)(t))(f((p => p(l => _ => l))(l)))(map((p => p(_ => r => r))(l))(f))))((es => (l => ((f => (x => f(n => x(x)(n)))(x => f(n => x(x)(n))))(rev => r => l => (l => is_undef((p => p(l => _ => l))(l)))(l)(_ => r)(_ => rev((h => t => (l => r => f => f(l)(r))(h)(t))((p => p(l => _ => l))(l))(r))((p => p(_ => r => r))(l)))))((l => r => f => f(l)(r))((_ => _)())((_ => _)()))(l))(es()))((f => (x => f(n => x(x)(n)))(x => f(n => x(x)(n))))(rcon => t => h => is_undef(h)(_ => t)(_ => rcon((h => t => (l => r => f => f(l)(r))(h)(t))(h)(t))))((l => r => f => f(l)(r))((_ => _)())((_ => _)()))(1)(2)(3)))(elem => elem - 1)

想要在 JavaScript 环境中执行上面的箭号函式的话,只需要有 的定义,也就是这个黑箱作为环境边界。is_undef

如果不打算将环境边界定得那么严格,可以将 替换为以下,就可以直接运算得到结果了:is_undef

n => n === (_ => _)() ? (f => y => f()) : (x => f => f())`,成為 `(f => (x => f(n => x(x)(n)))(x => f(n => x(x)(n))))(map => l => f => (l => (n => n === (_ => _)() ? (f => y => f()) : (x => f => f()))((p => p(l => _ => l))(l)))(l)(_ => ((l => r => f => f(l)(r))((_ => _)())((_ => _)())))(_ => (h => t => (l => r => f => f(l)(r))(h)(t))(f((p => p(l => _ => l))(l)))(map((p => p(_ => r => r))(l))(f))))((es => (l => ((f => (x => f(n => x(x)(n)))(x => f(n => x(x)(n))))(rev => r => l => (l => (n => n === (_ => _)() ? (f => y => f()) : (x => f => f()))((p => p(l => _ => l))(l)))(l)(_ => r)(_ => rev((h => t => (l => r => f => f(l)(r))(h)(t))((p => p(l => _ => l))(l))(r))((p => p(_ => r => r))(l)))))((l => r => f => f(l)(r))((_ => _)())((_ => _)()))(l))(es()))((f => (x => f(n => x(x)(n)))(x => f(n => x(x)(n))))(rcon => t => h => (n => n === (_ => _)() ? (f => y => f()) : (x => f => f()))(h)(_ => t)(_ => rcon((h => t => (l => r => f => f(l)(r))(h)(t))(h)(t))))((l => r => f => f(l)(r))((_ => _)())((_ => _)()))(1)(2)(3)))(elem => elem - 1)

还有可能再进一步吗? 例如, 中,连 1、2、3 甚至 都用箭号函式来表示? 似乎是可以挑战看看的对象...map(list(elems(1)(2)(3)))(elem => elem - 1)-

,