2016-07-28 16 views
10

K-combinator có thể được thực hiện như dưới đây và việc thực hiện không nên có bất kỳ tác dụng phụ.Sử dụng thực tế của K-combinator (Kestrel) trong javascript

const K = x => y => x; 

Đôi khi nó được gọi là "const" (như trong Haskell). Hàm K có thể được định nghĩa là "lấy một giá trị và trả về hàm unary (hằng số) luôn trả về giá trị đó."

Khi nào nó hữu ích? Xin hãy giúp tôi với các ví dụ thực tế.

+0

http://cs.stackexchange.com/questions/55441/what-is-the-purpose-of-the-ski-combinator-calculusor-even-lambda-calculus- wha –

+0

Có vẻ như hàm CL [constanty] (http://clhs.lisp.se/Body/f_cons_1.htm) đôi khi khá hữu ích. – Sylwester

+3

Trong ngôn ngữ được sử dụng, bạn sẽ sử dụng nó bất cứ khi nào bạn muốn gọi lại để bỏ qua đối số đầu tiên. – Bergi

Trả lời

2

Sự cố với K giống như với tất cả các bộ phối hợp nguyên thủy là bạn không thể tự mình cân nhắc nó. Các combinators nguyên thủy là các khối xây dựng cơ bản của lập trình hàm. Bạn cần một ngữ cảnh thích hợp để xem chúng tại nơi làm việc. Thách thức là lúng túng bối cảnh này, nếu bạn chưa quen với mô hình chức năng.

Dưới đây là "ngữ cảnh điển hình": Option. Trường hợp của các loại Option cũng giống như giá trị mà bạn có thể null, nhưng không bao giờ ném ra một lỗi khi áp dụng cho một chức năng:

// 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);

không K làm gì trong việc thực hiện điều này? Hãy kiểm tra dòng quan trọng:

f => o => Option.fold(x => Option.of(f(x))) (K(o)) (o) 

Option.fold hy vọng hai chức năng. Hàm được truyền đầu tiên x => Option.of(f(x)) là dành cho trường hợp some (có một giá trị). Số thứ hai K(o) cho trường hợp none (không có giá trị). Hãy nhớ rằng K mong đợi hai đối số K = x => y => {return x}. K(o) chỉ định o đến x. Bất kể thông tin thứ hai được chuyển là đối số thứ hai, K sẽ luôn bỏ qua y và trả lại x thay thế.

Nhưng o đại diện cho biểu thức K(o) là gì? Nó đại diện cho Option.none tức là sự vắng mặt của một giá trị. Vì vậy, khi ai đó cố gắng ánh xạ một hàm f trên none, none chỉ được trả về, bất kể số f chuyển làm đối số thứ hai cho K.

+0

Chức năng điều kiện tiên quyết "precon" ở đâu? –

1

Bộ kết hợp K cũng có thể được sử dụng làm giá trị chân lý, khi sử dụng các boolean được mã hóa bởi nhà thờ. I.e. IF-TEST THEN ELSE: nếu "IF-TEST" của bạn trả về K, thì "else" sẽ bị loại bỏ và "sau đó" sẽ được thực thi.

+0

bất kỳ đoạn mã nào? –

2

Sắp xếp một câu hỏi rộng, nhưng rất hay, tôi thích nó.

Để hỗ trợ ví dụ của tôi, trong câu trả lời này tôi sẽ triển khai & hellip;

abuild :: Number -> (Number -> a) -> [a] 

& hellip; như kiểu gợi ý, lấy một số và một hàm để xây dựng một mảng. Điều này có thể hữu ích nếu bạn muốn xây dựng một mảng có kích thước đã biết dựa trên một số tính toán.


Hãy tạo một mảng có 5 phần tử sử dụng chức năng nhận dạng, id.Như bạn có thể thấy, một chỉ số số tuần tự bắt đầu với 0 được trao cho builder bạn chức năng

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

Hãy làm điều gì đó toán học với người xây dựng lần này. Chúng tôi sẽ tạo hình vuông cho đầu vào. Rất tiên tiến.

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

Hoặc có thể chúng tôi không quan tâm đến đầu vào. Tôi luôn thích một tiếng cười tốt. Tôi luôn cười liên tục. Người ta có thể nói tôi K('ha') & hellip;

abuild (5) (K('ha')) 
// => ['ha','ha','ha','ha','ha'] 

Boom! Khá hữu ích, phải không? Đó là K


Thực hiện

Đi trước và chạy nó để xem K trong hành động!

// 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']

+0

Tôi thích các chức năng với sự hài hước: D là 'K (" ha ")' cười với hay về ai đó ?! – ftor

+1

Nó chỉ là một cái nhìn sâu sắc về tôi! Tôi thích làm cho ánh sáng của bất kỳ tình huống^_ ^ – naomik

Các vấn đề liên quan