在javascript中实际使用K-combinator(Kestrel)

Jyo*_*Pal 11 javascript functional-programming combinators

K-combinator可以如下实现,并且实现不应该有任何副作用.

const K = x => y => x;
Run Code Online (Sandbox Code Playgroud)

它有时被称为"const"(如在Haskell中).K函数可以定义为"获取一个值并返回一个始终返回该值的(常量)一元函数."

什么时候有用?请帮我提供实际例子.

小智 5

与所有原始组合器一样,问题K在于您不能单独考虑它。原语组合器是函数式编程的基本构建块。您需要一个适当的环境来观察他们的工作情况。如果您是函数范式的新手,那么挑战就在于理解这种背景。

这是一个“典型上下文” Option:该类型的实例Option类似于可能的值null,但在应用于函数时永远不会抛出错误:

// the option type

const Option = {
  some: Symbol.for("ftor/Option.some"),

  none: Symbol.for("ftor/Option.none"),

  of: x => factory(Option.some) (x),

  cata: pattern => o => pattern[o.tag](o.x),

  fold: f => g => o => Option.cata({[Option.some]: f, [Option.none]: g}) (o),

  map: f => o => Option.fold(x => Option.of(f(x))) (K(o)) (o)
  //                                                ^^^^
}


// a generic map function

const map = type => f => o => type.map(f) (o);


// functor factory

const factory = tag => value => (
  {x: value === undefined ? null : value, tag: tag}
);


// auxiliary functions

const K = x => y => x;
const sqr = x => x * x;


// a few data to play around

const o = factory(Option.some) (5);
const p = factory(Option.none) ();



// and run

let r1 = map(Option) (sqr) (o);
let r2 = map(Option) (sqr) (p);

console.log("map over o", r1);
console.log("map over p", r2);
Run Code Online (Sandbox Code Playgroud)

K这个实现中做了什么?让我们检查一下关键行:

f => o => Option.fold(x => Option.of(f(x))) (K(o)) (o)
Run Code Online (Sandbox Code Playgroud)

Option.fold期望有两个功能。第一个传递的函数x => Option.of(f(x))适用于这种some情况(有一个值)。第二个K(o)用于案例none(没有价值)。让我们回想一下,K需要两个参数K = x => y => {return x}K(o)分配ox. 无论作为第二个参数传递什么,K都将始终忽略y并返回x

o但表达式中代表什么K(o)?它代表 Option.none的是,值的缺失。因此,当有人尝试将函数映射f到时nonenone无论f第二个参数传递给什么,都会返回K


Tha*_*you 5

一个广泛的问题,但它很好,我喜欢它.

为了支持我的例子,我将在这个答案中实施......

abuild :: Number -> (Number -> a) -> [a]
Run Code Online (Sandbox Code Playgroud)

...根据类型的建议,需要一个数字和一个函数来构建一个数组.如果要根据某些计算构建已知大小的数组,这可能很有用.


让我们使用identity函数构建一个包含5个元素的数组id.如您所见,为构建函数提供了以0开头的顺序数字索引

abuild(5)(id)// => [0,1,2,3,4]

让我们这次与建造者做些蠢事.我们将对输入进行平方.非常先进.

abuild (5) (x=> x * x)
// => [0,1,4,9,16]
Run Code Online (Sandbox Code Playgroud)

或者也许我们不关心输入.我总是喜欢开怀大笑.我经常嘲笑事物.有人可以说我K('ha')......

abuild (5) (K('ha'))
// => ['ha','ha','ha','ha','ha']
Run Code Online (Sandbox Code Playgroud)

轰!非常有用,对吗?那是K


履行

继续运行它以查看K实际操作!

// id :: a -> a
const id = x=> x

// K :: a -> b -> a
const K = x=> y=> x

// add :: Number -> Number -> Number
const add = x=> y=> y + x

// reduce :: (a -> b) -> b -> [a] -> b 
const reduce = f=> y=> ([x,...xs])=> {
  if (x === undefined)
    return y
  else
    return reduce (f) (f (y) (x)) (xs)
}

// map :: (a -> b) -> [a] -> [b]
const map = f=> reduce (xs=> x=> [...xs, f(x)]) ([])

// iterate :: Number -> (a -> a) -> a -> [a]
const iterate = n=> f=> x=>
  n > 0 ? [x, ...iterate (n - 1) (f) (f(x))] : []

// abuild :: Number -> (Number -> a) -> [a]
const abuild = n=> f=>
  map (f) (iterate (n) (add (1)) (0))

console.log(abuild (5) (id))
// => [0,1,2,3,4]

console.log(abuild (5) (x=> x * x))
// => [0,1,4,9,16]

console.log(abuild (5) (K('ha')))
// => ['ha','ha','ha','ha','ha']
Run Code Online (Sandbox Code Playgroud)