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のfunctor prototcolには従っておらず、各functorはそのプロトタイプ上にmap関数を所有していなければなりません。 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

optionは明らかにモナドのようなタイプ(少なくとも、それは私の例では1のように振舞う)に拡張することができます。コールスタックにコンテキスト(または効果)計算の結果が保持されている(純粋な)高次関数を持つすべてのファンクタ/モナドを単独で表現することは可能ですか?

+0

は、なぜあなたはこれをしたいですか?他の解決方法がありますか? – niceman

+0

@ftor [Church encoding](https://en.wikipedia.org/wiki/Church_encoding)のようなものを意味しますか? – phg

+0

@phg理論的根拠、ありがとう。理論的には可能です。私はまだJavascriptでそれらを実装する実用的な問題があるかどうか疑問に思います。これまで 'option'には(proto)型はありません。関数( 'of'のような)を右のモナドに関連付けるにはどうすればいいですか?さらに、 'option'は共用体にすぎません。タグがなく、組合が採用した可能性のあるタイプを反映する手段がない。 – ftor

答えて

1

もちろんです。関数はすべてのことを行うことができます。とにかく、あなたはあなただけが表示されます下のカップルJSプリミティブ別に

*+Number、および String)は、機能性を実証する^ _ ^提供するために全力を試してみてください、私はつもりだ知っているので、それを求め:それは共同ではありません

  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

ええ、それはタイプクラスのようなものを扱う - 便利にtho、両方のオプションとタイプは独自の "メソッド"を定義することができます – naomik

関連する問題