2

我試圖在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,其中上下文(或有效)計算的結果保存在調用堆棧中?

+0

你爲什麼要這麼做?如果「瀏覽器中的haskell」是你的目標還有其他解決方案 – niceman

+0

@ftor你的意思是類似[教會編碼](https://en.wikipedia.org/wiki/Church_encoding)? – phg

+0

@phg的理論基礎,謝謝。所以這在理論上是可能的。我仍然懷疑是否有實際問題在Javascript中實現它們。到目前爲止,'option'沒有(proto)類型。我如何將函數(如''')與正確的monad關聯?而且,'option'只是一個聯盟。沒有標籤也沒有辦法反映工會採用哪種類型。 – ftor

回答

1

當然。函數幾乎可以做任何事情。無論如何,你自找的,所以你知道我會盡我所能提供^ _^

從幾個JS元

除了(*+NumberString)演示功能,下面你將只能看到:

  1. 變量
  2. 拉姆達抽象
  3. 應用

這不是一個合作這些都是(本質上)λ演算的3個基本構件。

const identity = x => x 
 
const fromNullable = x => x == null ? None : Option(x) 
 

 
const Option = (value) => k => { 
 
    const join =() => value 
 
    const map = f => Option(f(value)) 
 
    const bind = f => f(value) 
 
    const ap = m => optionMap(value)(m) 
 
    const fold = f => f(value) 
 
    return k (value, join, map, bind, ap, fold) 
 
} 
 

 
const None =() => k => { 
 
    const join = identity 
 
    const map = f => None() 
 
    const bind = f => None() 
 
    const ap = m => None() 
 
    const fold = f => f(null) 
 
    return k (null, join, map, bind, ap, fold) 
 
} 
 

 
const optionJoin = m => m((value, join, map, bind, ap, fold) => join()) 
 
const optionMap = f => m => m((value, join, map, bind, ap, fold) => map(f)) 
 
const optionBind = f => m => m((value, join, map, bind, ap, fold) => bind(f)) 
 
const optionAp = n => m => m((value, join, map, bind, ap, fold) => ap(n)) 
 
const optionFold = f => m => m((value, join, map, bind, ap, fold) => fold(f)) 
 

 
optionFold (console.log) (Option(5)) // 5 
 
optionFold (console.log) (None()) // null 
 

 
optionFold (console.log) (optionMap (x => x * 2) (Option(5))) // 10 
 
optionFold (console.log) (optionMap (x => x * 2) (None()))// null 
 

 
optionFold (console.log) (optionAp(Option(3)) (Option(x => x + 4))) // 7 
 
optionFold (console.log) (optionAp(Option(3)) (None())) // null 
 

 
optionFold (console.log) (optionBind(x => Option(x * x)) (Option(16))) // 256 
 
optionFold (console.log) (optionBind(x => Option(x * x)) (None())) // null 
 

 
optionFold (console.log) (optionJoin (Option(Option('hi')))) // 'hi' 
 
optionFold (console.log) (optionJoin (Option(None())))// null

+0

我期待着討論,如果你有興趣,當然^ _^ – naomik

+0

你把整個API放到'Option'類型中。這就說得通了。我會稍微玩一下,稍後再回來。 – ftor

+0

耶對待它有點像一個類型的類 - 方便壽,選項和無類型可以定義自己的「方法」 – naomik