K-combinator可以如下实现,实现不应有任何副作用。
const K = x => y => x;
它有时被称为“const”(如在Haskell中)。 K函数可以定义为“获取一个值并返回一个始终返回该值的(常量)一元函数。”
什么时候有用?请帮我提供实例。
答案 0 :(得分:5)
一个广泛的问题,但它很好,我喜欢它。
为了支持我的例子,在这个答案中,我将实施......
abuild :: Number -> (Number -> a) -> [a]
...如类型所示,需要一个数字和一个函数来构建一个数组。如果要根据某些计算构建已知大小的数组,这可能很有用。
让我们使用身份函数id
构建一个包含5个元素的数组。如您所见,为 builder 函数
abuild(5)(id) // => [0,1,2,3,4]
这次让我们对建造者做些蠢事。我们将对输入进行平方。非常先进。
abuild (5) (x=> x * x)
// => [0,1,4,9,16]
或者我们可能不关心输入。我总是喜欢开怀大笑。我经常嘲笑事物。可以说我K('ha')
...
abuild (5) (K('ha'))
// => ['ha','ha','ha','ha','ha']
轰隆隆!非常有用,对吗?那是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']
答案 1 :(得分:3)
与所有原始组合器一样,K
的问题在于您无法单独考虑它。原始组合器是函数式编程的基本构建块。你需要一个适当的环境来观察他们的工作。如果您不熟悉功能范例,那么挑战在于了解这一背景。
这是一个典型的背景&#34;: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);
&#13;
K
在此实施中做了什么?让我们来看看关键路线:
f => o => Option.fold(x => Option.of(f(x))) (K(o)) (o)
Option.fold
需要两个功能。第一个传递函数x => Option.of(f(x))
用于some
情况(有一个值)。 K(o)
案例的第二个none
(没有值)。让我们回想起K
期望两个参数K = x => y => {return x}
。 K(o)
将o
分配给x
。无论作为第二个参数传递什么,K
将始终忽略y
并返回x
。
但是o
表达式K(o)
中的含义是什么?它代表Option.none
即没有值。因此,当有人尝试将函数f
映射到none
时,只会返回none
,无论f
作为第二个参数传递给K
。
答案 2 :(得分:1)