我試圖在Javascript中實現函子而不使用容器類型([]
/{}
)。因此,我僅利用純高階函數來構造它們:函子或單子可以分別用高階函數表示嗎?
const option = x => f => isAssigned(x) ? option(f(x)) : none;
const none = option(null);
const isAssigned = x => x !== null && x !== undefined;
const inc = x => x + 1;
const sqr = x => x * x;
const head = xs => xs[0]
const log = x => (console.log(x), x);
option(head([4])) (inc) (sqr) (log); // 25
option(head([])) (inc) (sqr) (log); // not executed
option
取值和一個純函數,升降機的功能到其上下文中,它適用於值,並返回導致相同的上下文。我想這是一個仿函數。但是,它並不遵循Javascript中的函數原型,每個函子都必須擁有其原型上的映射函數。
option
顯然可以擴展到一個單子樣型(至少它的行爲就像一個在我的例子):本發明提供option
const option = x => f => isAssigned(x) ? option(f(x)) : none;
const option_ = x => f => isAssigned(x) ? flatten(option(f(x))) : none;
const none = option(null);
const of = x => option(x); // return
const flatten = F => { // it gets a bit ugly here
let y;
F(z => (y = z, z));
return y;
};
// auxiliary functions
const compn = (...fs) => x => fs.reduceRight((acc, f) => f(acc), x);
const getOrElse = x => F => {
let y;
F(z => (y = z, z));
return isAssigned(y) ? y : x;
};
const isAssigned = x => x !== null && x !== undefined;
const log = prefix => x => (console.log(prefix, x), x);
const head = xs => xs[0];
const head_ = xs => option(xs[0]);
const sqr = x => x * x;
// some data
const xs = [5],
ys = [];
// run
const w = option(xs) (head),
x = option(ys) (head),
y = option_(xs) (head_),
z = option_(ys) (head_);
log("square head of xs:") (compn(sqr, getOrElse(1)) (w)); // 25
log("square head of ys:") (compn(sqr, getOrElse(0)) (x)); // 0
log("square head_ of xs:") (compn(sqr, getOrElse(0)) (y)); // 25
log("square head_ of ys:") (compn(sqr, getOrElse(0)) (z)); // 0
實際上是一個算符我的問題是:是否有可能僅使用(純)更高階函數來表示每個函子/ monad,其中上下文(或有效)計算的結果保存在調用堆棧中?
你爲什麼要這麼做?如果「瀏覽器中的haskell」是你的目標還有其他解決方案 – niceman
@ftor你的意思是類似[教會編碼](https://en.wikipedia.org/wiki/Church_encoding)? – phg
@phg的理論基礎,謝謝。所以這在理論上是可能的。我仍然懷疑是否有實際問題在Javascript中實現它們。到目前爲止,'option'沒有(proto)類型。我如何將函數(如''')與正確的monad關聯?而且,'option'只是一個聯盟。沒有標籤也沒有辦法反映工會採用哪種類型。 – ftor