ทำไมนิทานพื้นบ้านกับรามดาจึงแตกต่างกัน?


97

ฉันเรียนรู้ FP JavaScript โดยการอ่าน DrBoolean ของหนังสือ

ฉันค้นหาห้องสมุดโปรแกรมการทำงาน พบรามดาและนิทานพื้นบ้าน ทั้งสองอ้างว่าเป็นไลบรารีการเขียนโปรแกรมที่ใช้งานได้

แต่แตกต่างกันมาก:

  • Ramdaดูเหมือนจะมีฟังก์ชั่นยูทิลิตี้สำหรับจัดการกับ list: map, reduction , filter และ pure functions: curry, compose มันไม่มีอะไรที่ต้องจัดการกับ monad, functor

  • อย่างไรก็ตามนิทานพื้นบ้านไม่มียูทิลิตี้สำหรับรายการหรือฟังก์ชันใด ๆ ดูเหมือนว่าจะใช้โครงสร้างพีชคณิตบางอย่างในจาวาสคริปต์เช่น monad: Maybe, Task ...

อันที่จริงฉันพบห้องสมุดมากกว่านี้ดูเหมือนทั้งหมดจะอยู่ในสองหมวดหมู่ ขีดล่างและ lodash เหมือน Ramda Fantasy-land, pointfree-fantasy เป็นเหมือนนิทานพื้นบ้าน

ไลบรารีที่แตกต่างกันมากเหล่านี้สามารถเรียกว่าfunctional ได้หรือไม่และถ้าเป็นเช่นนั้นอะไรทำให้แต่ละไลบรารีใช้งานได้


1
ใช้สิ่งที่เหมาะกับความต้องการและสไตล์ของคุณและได้รับการบันทึกไว้เป็นอย่างดี
charlietfl

1
ฉันพบว่ามีความหมายโดยทั่วไปสามความหมายสำหรับ "การเขียนโปรแกรมเชิงฟังก์ชัน" โดยเฉพาะใน JS 1. ใช้ลำดับที่สูงกว่าฟังก์ชั่นที่บริสุทธิ์ในชุดเช่นอาร์เรย์. อดีต[1,2,3].map(fnSquare).reduce(fnSum)2. นักวิชาการส่วนใหญ่ "ดูแม่ไม่มีvar " โครงสร้าง Y-Combinator ฟีเจอร์ 3. ใช้Function.prototypeแก้ไขการทำงานของฟังก์ชันอื่นเช่นvar isMissingID=fnContains.partial("id").negate();
dandavis

11
ผู้เขียน Ramda ที่นี่: Ramda เป็นไลบรารียูทิลิตี้ที่ค่อนข้างต่ำ มีจุดมุ่งหมายเพื่อทำให้รูปแบบการทำงานบางอย่างง่ายขึ้นใน JS โดยเฉพาะการทำงานโดยการเขียนฟังก์ชัน Ramda ทำงานได้ดีกับข้อกำหนด FantasyLand รวมถึงการใช้งานเช่น Folktale ห้องสมุดเหล่านี้ได้รับการออกแบบมาเพื่อวัตถุประสงค์ที่แตกต่างกัน พวกเขาสร้างขึ้นจากการจดจำประเภทข้อมูลนามธรรมทั่วไปและอนุญาตให้เข้าถึงได้อย่างสม่ำเสมอเช่น Monoids, Functors และ Monads Ramda จะทำงานร่วมกับพวกเขาและมีโครงการด้านข้างเพื่อสร้างบางส่วน แต่ก็เป็นอย่างที่คุณพูดจุดเน้นที่แตกต่างกันมาก
Scott Sauyet

1
@KeithNicholas: ใช่มีห้อง Gitter
Scott Sauyet

2
ลองดู Sanctuary ด้วย - github.com/plaid/sanctuary นี่ขึ้นอยู่กับ ramda แต่ยังครอบคลุมถึงประเภทแฟนตาซีแลนด์ด้วย
arcseldon

คำตอบ:


182

คุณสมบัติการทำงาน

ไม่มีขอบเขตที่ชัดเจนของสิ่งที่กำหนดการเขียนโปรแกรมเชิงฟังก์ชันหรือไลบรารีการทำงาน คุณลักษณะบางอย่างของภาษาที่ใช้งานได้มีอยู่ใน Javascript:

  • ฟังก์ชั่นชั้นหนึ่งลำดับที่สูงกว่า
  • ฟังก์ชัน Lambdas / Anonymous พร้อมการปิด

คนอื่น ๆ สามารถทำได้ใน Javascript ด้วยความระมัดระวัง:

  • ไม่เปลี่ยนรูป
  • ความโปร่งใสในการอ้างอิง

ส่วนอื่น ๆ ยังคงเป็นส่วนหนึ่งของ ES6 และมีให้บริการบางส่วนหรือทั้งหมดในขณะนี้:

  • ฟังก์ชั่นกะทัดรัดแม้จะสั้น
  • การเรียกซ้ำของผู้ดำเนินการผ่านการเพิ่มประสิทธิภาพการโทรหาง

และยังมีสิ่งอื่น ๆ อีกมากมายที่เกินกว่า Javascript ปกติ:

  • การจับคู่รูปแบบ
  • ขี้เกียจประเมิน
  • Homoiconicity

จากนั้นไลบรารีสามารถเลือกและเลือกประเภทของคุณลักษณะที่พยายามสนับสนุนและยังคงเรียกว่า "ใช้งานได้" ได้อย่างสมเหตุสมผล

ข้อกำหนดแฟนตาซีที่ดิน

แฟนตาซีที่ดินเป็นข้อกำหนดสำหรับจำนวนของชนิดมาตรฐานรังเพลิงจากหมวดหมู่คณิตศาสตร์ทฤษฎีและพีชคณิตนามธรรมในการเขียนโปรแกรมการทำงานประเภทเช่นหนังสือ , FunctorและMonad ประเภทเหล่านี้ค่อนข้างเป็นนามธรรมและอาจขยายความคิดที่คุ้นเคยมากขึ้น ตัวอย่างเช่น Functors เป็นคอนเทนเนอร์ที่สามารถmapข้ามไปมาได้ด้วยฟังก์ชันวิธีที่อาร์เรย์สามารถmapใช้งานArray.prototype.mapได้

นิทานพื้นบ้าน

Folktaleคือชุดของประเภทที่ใช้ส่วนต่างๆของข้อกำหนด Fantasy-land และชุดฟังก์ชันยูทิลิตี้ที่ใช้ร่วมกันเล็กน้อย ประเภทเหล่านี้เป็นสิ่งที่ชอบบางที , ทั้ง , Task (คล้ายกับสิ่งที่เรียกว่าที่อื่น ๆ ในอนาคตและญาติถูกต้องตามกฎหมายมากขึ้นที่จะเป็นสัญญา) และการตรวจสอบ

นิทานพื้นบ้านอาจเป็นการนำข้อกำหนด Fantasy-land ที่รู้จักกันดีที่สุดมาใช้และเป็นที่ยอมรับนับถือ แต่ไม่มีสิ่งที่เรียกว่าการใช้งานขั้นสุดท้ายหรือเริ่มต้น ดินแดนแฟนตาซีระบุเฉพาะประเภทนามธรรมและการดำเนินการตามหลักสูตรจะต้องสร้างประเภทคอนกรีตดังกล่าว การอ้างสิทธิ์ของ Folktale ในการเป็นไลบรารีที่ใช้งานได้นั้นมีความชัดเจน: มีประเภทข้อมูลที่พบโดยทั่วไปในภาษาโปรแกรมที่ใช้งานได้ซึ่งทำให้โปรแกรมในลักษณะการทำงานง่ายขึ้นอย่างมาก

ตัวอย่างนี้จากเอกสารนิทานพื้นบ้าน ( หมายเหตุ : ไม่ได้อยู่ในเอกสารเวอร์ชันล่าสุด) แสดงให้เห็นถึงวิธีการใช้:

// We load the library by "require"-ing it
var Maybe = require('data.maybe')

// Returns Maybe.Just(x) if some `x` passes the predicate test
// Otherwise returns Maybe.Nothing()
function find(predicate, xs) {
  return xs.reduce(function(result, x) {
    return result.orElse(function() {
      return predicate(x)?    Maybe.Just(x)
      :      /* otherwise */  Maybe.Nothing()
    })
  }, Maybe.Nothing())
}

var numbers = [1, 2, 3, 4, 5]

var anyGreaterThan2 = find(function(a) { return a > 2 }, numbers)
// => Maybe.Just(3)

var anyGreaterThan8 = find(function(a) { return a > 8 }, numbers)
// => Maybe.Nothing

รามดา

Ramda (ข้อจำกัดความรับผิดชอบ: ฉันเป็นหนึ่งในผู้เขียน) เป็นห้องสมุดประเภทที่แตกต่างกันมาก ไม่มีประเภทใหม่ให้คุณ 1 แต่มีฟังก์ชันเพื่อให้ใช้งานประเภทที่มีอยู่ได้ง่ายขึ้น มันถูกสร้างขึ้นจากแนวคิดของการเขียนฟังก์ชันที่เล็กลงให้เป็นฟังก์ชันที่ใหญ่ขึ้นการทำงานกับข้อมูลที่ไม่เปลี่ยนรูปเพื่อหลีกเลี่ยงผลข้างเคียง

Ramda ทำงานโดยเฉพาะอย่างยิ่งในรายการ แต่ยังอยู่ในวัตถุและบางครั้งใน Strings นอกจากนี้ยังมอบหมายการเรียกร้องจำนวนมากในลักษณะที่จะทำงานร่วมกับ Folktale หรือการใช้งาน Fantasy-land อื่น ๆ ยกตัวอย่างเช่น Ramda ของmapฟังก์ชั่นดำเนินการในทำนองเดียวกันกับหนึ่งบนดังนั้นArray.prototype R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]แต่เนื่องจาก Folktale Maybeใช้ข้อกำหนด Fantasy-land Functorซึ่งระบุแผนที่ด้วยคุณจึงสามารถใช้ Ramda ได้mapด้วย:

R.map(square, Maybe.Just(5)); //=> Maybe.Just(25);
R.map(square, Maybe.Nothing); //=> Maybe.Nothing

Ramda อ้างว่าเป็นไลบรารีที่ใช้งานได้จริงในการทำให้ง่ายต่อการเขียนฟังก์ชันไม่เปลี่ยนข้อมูลของคุณและนำเสนอเฉพาะฟังก์ชันที่บริสุทธิ์เท่านั้น การใช้ Ramda โดยทั่วไปคือการสร้างฟังก์ชันที่ซับซ้อนมากขึ้นโดยการจัดองค์ประกอบให้เล็กลงดังที่เห็นในบทความเกี่ยวกับปรัชญาของ Ramda

// :: [Comment] -> [Number]  
var userRatingForComments = R.pipe(
    R.pluck('username')      // [Comment] -> [String]
    R.map(R.propOf(users)),  // [String] -> [User]
    R.pluck('rating'),       // [User] -> [Number]
);

ห้องสมุดอื่น ๆ

อันที่จริงฉันพบห้องสมุดมากกว่านี้ดูเหมือนว่าทั้งหมดจะอยู่ในสองหมวดหมู่ ขีดล่าง lodash เหมือน Ramda มาก Fantasy-land, pointfree-fantasy เป็นเหมือนนิทานพื้นบ้าน

นั่นไม่ถูกต้องจริงๆ ประการแรก Fantasy-land เป็นเพียงข้อกำหนดที่ห้องสมุดสามารถตัดสินใจนำไปใช้กับประเภทต่างๆได้ นิทานพื้นบ้านเป็นหนึ่งในการปรับใช้ข้อกำหนดดังกล่าวอาจเป็นสิ่งที่ดีที่สุดและเป็นผู้ใหญ่ที่สุด Pointfree แฟนตาซีและramda แฟนตาซีคนอื่น ๆ และมีอื่น ๆ อีกมากมาย

ขีดล่างและlodashนั้นดูเผินๆเหมือน Ramda ตรงที่เป็นห้องสมุดแบบกระเป๋าถือซึ่งมีฟังก์ชั่นจำนวนมากโดยมีการทำงานร่วมกันน้อยกว่าของ Folktale และแม้แต่ฟังก์ชันการทำงานเฉพาะก็มักจะทับซ้อนกับ Ramda แต่ในระดับที่ลึกกว่านั้น Ramda มีข้อกังวลที่แตกต่างจากห้องสมุดเหล่านั้นมาก ญาติที่ใกล้เคียงที่สุดของ Ramda อาจจะเป็นห้องสมุดเช่นFKit , FnucและWu.js

Bilbyอยู่ในหมวดหมู่ของตัวเองโดยมีทั้งเครื่องมือมากมายเช่นเครื่องมือที่ Ramda จัดหาให้และบางประเภทก็สอดคล้องกับ Fantasy-land (ผู้แต่ง Bilby เป็นผู้แต่ง Fantasy-land เช่นกัน)

การโทรของคุณ

ไลบรารีทั้งหมดเหล่านี้มีสิทธิ์ถูกเรียกว่าฟังก์ชันแม้ว่าจะแตกต่างกันอย่างมากในแนวทางการทำงานและระดับความมุ่งมั่นในการทำงาน

ห้องสมุดเหล่านี้บางส่วนทำงานร่วมกันได้ดี Ramda ควรทำงานได้ดีกับ Folktale หรือการใช้งาน Fantasy-land อื่น ๆ เนื่องจากความกังวลของพวกเขาแทบจะไม่ทับซ้อนกันพวกเขาจึงไม่ขัดแย้งกัน แต่ Ramda ก็เพียงพอแล้วที่จะทำให้การทำงานร่วมกันเป็นไปอย่างราบรื่น นี่อาจเป็นความจริงน้อยกว่าสำหรับชุดค่าผสมอื่น ๆ ที่คุณสามารถเลือกได้ แต่ไวยากรณ์ของฟังก์ชันที่ง่ายกว่าของ ES6 อาจช่วยลดความเจ็บปวดจากการผสานรวมได้

การเลือกไลบรารีหรือแม้แต่รูปแบบของไลบรารีที่จะใช้นั้นขึ้นอยู่กับโปรเจ็กต์และความชอบของคุณ มีตัวเลือกที่ดีมากมายให้เลือกและตัวเลขก็เพิ่มขึ้นเรื่อย ๆ และหลายตัวเลือกที่ดีขึ้นอย่างมาก เป็นเวลาที่ดีที่จะเขียนโปรแกรมเชิงฟังก์ชันใน JS


1มีไซด์โปรเจ็กต์รามดาแฟนตาซีทำอะไรคล้าย ๆโฟล์กเทลแต่ไม่ได้เป็นส่วนหนึ่งของไลบรารีหลัก


1
จะยุติธรรมหรือไม่ที่จะบอกว่า ES6 มีความสามารถในการประเมินผลแบบขี้เกียจด้วยการแนะนำ Yield developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Marcel Lamothe

8
ฉบับที่ yieldทำให้ง่ายต่อการทำทุกประเภทของรายการขี้เกียจการประมวลผลที่ทำโดยหรือLazy lz.jsแต่มันไม่ได้ช่วยเรื่องความขี้เกียจระดับภาษา someFunc(a + b)ใน JS แรกเพิ่มค่าของaและbแล้วเครื่องผลที่เป็นพารามิเตอร์เพื่อ someFunc เทียบเท่าใน Haskell ไม่ทำเช่นนั้น ถ้าฟังก์ชันที่เรียกว่าไม่เคยใช้ค่านั้นฟังก์ชันนี้จะไม่ทำการเพิ่ม หากในที่สุดก็ใช้มันจะถือว่านิพจน์ถูกคำนวณจนกว่าจะได้ผลลัพธ์ที่ต้องการ หากคุณไม่เคยทำอะไรที่จะบังคับมัน (เช่น IO) มันจะไม่ทำการคำนวณจริง
Scott Sauyet

@ScottSauyet บางทีคุณอาจโต้แย้งว่า "การประเมินแบบขี้เกียจ" ในบางรูปแบบสามารถใช้ได้ผ่านเครื่องกำเนิดไฟฟ้า ES6 เช่นเฟรมเวิร์ก JS จำนวนมากมีลักษณะ "ความเกียจคร้าน" - RxJs, ImmutableJs เป็นต้น
arcseldon

9
คำตอบนี้ควรเป็นบทหรือส่วนหนึ่งในหนังสือของ DrBoolean :)
เส

1
เอกสาร Ramda มีแนวโน้มที่จะใช้ "list" เป็นชวเลขสำหรับสิ่งที่ใกล้เคียงที่สุดที่ JS เสนอในรายการอาร์เรย์หนาแน่น สิ่งเหล่านี้มีลักษณะการทำงานที่แตกต่างจากรายการที่แท้จริงและแน่นอนว่าเป็น API ที่แตกต่างกันเล็กน้อย แต่สามารถใช้เพื่อวัตถุประสงค์เดียวกันได้มากและเป็นประเภทเนทีฟที่ใกล้เคียงที่สุด (แต่ดูgithub.com/funkia/list ) ที่มีให้สำหรับ Ramda API ซึ่งตามแนวคิดแล้วต้องการทำงานกับรายการที่บริสุทธิ์ ฉันจะเถียงจุดอาร์เรย์ที่ไม่เป็นจริงเนื่องจากอาร์เรย์สไตล์ C ไม่ได้เป็นที่ยอมรับมากไปกว่า JS และไม่มีอะไรใกล้เคียงกับทางคณิตศาสตร์เลย แต่นั่นเป็นประเด็นเล็กน้อย
Scott Sauyet
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.