การเขียนโปรแกรมเชิงฟังก์ชันละเลยประโยชน์ที่ได้รับจาก“ ตามเกณฑ์ที่จะใช้ในการย่อยสลายระบบเป็นโมดูล” (การซ่อนข้อมูล) หรือไม่?


27

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

เราพยายามสาธิตโดยตัวอย่างเหล่านี้ว่ามันไม่ถูกต้องเสมอไปที่จะเริ่มการสลายตัวของระบบเป็นโมดูลบนพื้นฐานของแผนผังลำดับงาน ... แต่ละโมดูลได้รับการออกแบบมาเพื่อซ่อนการตัดสินใจจากสิ่งอื่น

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

  1. ก่อนอื่นฉันต้องการทราบว่าการประเมินของฉันถูกต้องหรือไม่ กระบวนทัศน์ของ FP และบทความนี้ขัดแย้งกับปรัชญาหรือไม่?
  2. สมมติว่าพวกเขาไม่เห็นด้วย FP จะ "ชดเชย" อย่างไรหากไม่มีการซ่อนข้อมูล บางทีพวกเขาอาจเสียสละการซ่อนข้อมูล แต่ได้รับ X, Y และ Z ฉันต้องการทราบเหตุผลว่าทำไม X, Y และ Z จึงถือว่าเป็นประโยชน์มากกว่าการซ่อนข้อมูล
  3. หรือสมมติว่าพวกเขาไม่เห็นด้วย FP อาจรู้สึกว่าการซ่อนข้อมูลไม่ดี ถ้าเป็นเช่นนั้นทำไมจึงคิดว่าการซ่อนข้อมูลไม่ดี
  4. สมมติว่าพวกเขาเห็นด้วยฉันต้องการทราบว่าการนำ FPs ไปปฏิบัติใช้ของการซ่อนข้อมูลคืออะไร เห็นได้ชัดใน OOP คุณสามารถมีprivateฟิลด์ที่ไม่มีใครนอกชั้นเรียนสามารถเข้าถึงได้ ไม่มีสิ่งใดที่เปรียบเทียบกับฉันใน FP
  5. ฉันรู้สึกว่ามีคำถามอื่น ๆ ที่ฉันควรถาม แต่ฉันไม่รู้ว่าควรถาม อย่าลังเลที่จะตอบคำถามเหล่านั้นเช่นกัน

ปรับปรุง

ฉันพบการพูดคุยของ Neal Fordที่มีสไลด์ที่เกี่ยวข้องมาก ฉันจะฝังภาพหน้าจอที่นี่:

ป้อนคำอธิบายรูปภาพที่นี่


1
ฉันไม่สามารถตอบคำถามเต็ม แต่สำหรับ (4) มีระบบโมดูลในภาษา FP บางอย่างที่สามารถให้การห่อหุ้ม
Andres F.

@AndresF ใช่แล้วมันเป็นเรื่องจริง ฉันลืมว่า Haskell มีโมดูลและคุณสามารถซ่อนประเภทข้อมูลและฟังก์ชั่นในพวกเขา บางทีเมื่อฉันพูด FP ฉันกำลังพูดว่า Clojure คุณสามารถมีฟังก์ชั่นส่วนตัวและ "ช่อง" ใน Clojure แต่ฉันรู้สึกเหมือนมันเป็นสำนวนที่ทำให้ข้อมูลของคุณปรากฏต่อทุกสิ่งและส่งผ่านทุกที่
Daniel Kaplan

6
สิ่งที่คุณมักจะทำคือทำให้ประเภทของคุณปรากฏ แต่ซ่อนตัวสร้างของคุณ ประเภทนามธรรมเหล่านี้ทำได้ดีเป็นพิเศษโดยระบบโมดูล OCaml
Daniel Gratzer

6
ในภาษาที่คล้ายกับ ML ไม่มีการเข้าถึงตัวสร้างหมายความว่าคุณไม่สามารถจับคู่รูปแบบกับค่าของประเภทนั้นเพื่อแยกโครงสร้าง สิ่งเดียวที่คุณสามารถทำได้กับค่าเหล่านั้นคือการส่งผ่านไปยังฟังก์ชันใด ๆ ก็ตามที่มีให้ มันเป็นข้อมูลที่เป็นนามธรรมเช่นเดียวกับที่ทำเสร็จแล้วพูดว่า C ซึ่งไม่มีความคิดชั้นหนึ่งเกี่ยวกับสิ่งที่เป็นสาธารณะหรือส่วนตัวเช่นกัน
Luc Danton

1
@ SK-logic: จากมุมมอง "ปัญหาการแสดงออก" การเปิดเผยข้อมูลเป็นสิ่งที่ดีเมื่อคุณต้องการขยายด้วยฟังก์ชั่นใหม่ในอนาคต (และตกลงกับการรักษาข้อมูลให้คงที่) และการซ่อนข้อมูลนั้นดีเมื่อคุณต้องการ ที่จะขยายกับประเภทข้อมูลใหม่ในอนาคต (ที่ค่าใช้จ่ายของการรักษาอินเตอร์เฟซการทำงานคงที่)
hugomg

คำตอบ:


23

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

ฟังก์ชั่นที่ได้รับการออกแบบมาอย่างดีไม่ได้คิดเกี่ยวกับข้อมูลมากกว่าที่พวกเขาต้องการดังนั้นส่วนที่เกี่ยวกับ "การรับรู้ข้อมูลอย่างใกล้ชิด" นั้นผิด (หรืออย่างน้อยก็ผิดตามที่ควรจะเป็นของ OOP คุณไม่สามารถตั้งโปรแกรมในระดับสูงอย่างเป็นนามธรรมและละเว้นรายละเอียดทั้งหมดตลอดไปในกระบวนทัศน์ใด ๆ ในท้ายที่สุดบางส่วนของโปรแกรมจำเป็นต้องรู้เกี่ยวกับ รายละเอียดเฉพาะของข้อมูล)

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

แก้ไข: ผมพบว่าคำพูดที่เกี่ยวข้องจากการให้สัมภาษณ์กับรวย Hickey

Fogus: ตามความคิดนั้น - บางคนประหลาดใจกับความจริงที่ว่า Clojure ไม่ได้มีส่วนร่วมในการซ่อนข้อมูลในประเภทของมัน ทำไมคุณถึงตัดสินใจทิ้งการซ่อนข้อมูลไว้?

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


2
โปรแกรมเมอร์ OO ไม่ต้องการให้ทุกสิ่งเป็นวัตถุ แต่บางสิ่ง (หลายสิ่ง) ได้รับประโยชน์จากการห่อหุ้ม ฉันมีปัญหาในการเข้าใจว่าคำตอบของคุณตอบคำถามอย่างไร ดูเหมือนจะเป็นการยืนยันว่าแนวคิดนั้นไม่เฉพาะเจาะจงกับ OOP และ OOP นั้นมีปัญหาอื่น ๆ และต่อ ๆ ไปเรื่อย ๆ คุณอาจให้ตัวอย่างที่ชัดเจนแม้ว่ามันจะเป็น pseudocode เพียงไม่กี่บรรทัดก็ตาม หรือคำอธิบายไวท์บอร์ดของการออกแบบที่คำนึงถึงสิ่งนี้? หรืออะไรก็ตามที่ยืนยันการยืนยันที่นี่?
Aaronaught

2
@Anaught: ฉันพูดถึงจุดต่างๆที่เกิดขึ้นในคำถาม (และไม่ใช่ทั้งหมด) และอ้างอิงบทความเกี่ยวกับการเขียนโปรแกรมการทำงานที่ดูเป็นโมดูลในลักษณะที่คล้ายกับกระดาษในคำถาม ในระดับใหญ่ความจริงที่ว่าแนวคิดไม่เฉพาะเจาะจงกับ OOP คือคำตอบสำหรับคำถามของเขา (เว้นแต่ฉันจะเข้าใจผิดคำถามทั้งหมด) ฉันไม่ได้พูดถึง OOP ที่มีปัญหาอื่น ๆ ที่นี่ คุณมีจุดที่ดีเกี่ยวกับการให้ตัวอย่าง ฉันจะดูว่าฉันสามารถเกิดขึ้นกับคนดี
Michael Shaw

2
"บางครั้งโครงสร้างข้อมูลที่เรียบง่ายก็เป็นสิ่งที่คุณต้องการ" +1 บางสิ่งที่ OOP เข้าท่าบางครั้งก็เป็น FP
Laurent Bourgault-Roy

1
@Aaraught คำตอบนี้ชี้ให้เห็นถึงความเป็นโมดุล (ซึ่งเป็นทั้งการห่อหุ้มและการนำกลับมาใช้ใหม่) เป็นหนึ่งในเป้าหมายของ FP (ดังที่กล่าวไว้ในหัวข้อ ไม่"
Andres F.

2
การซ่อนข้อมูล @JimmyHoffa เป็นหลักการที่มีเหตุผลแม้อยู่นอก OO ในฮาเซลฉันยังต้องการให้ผู้ใช้สามารถทำงานด้วยความรู้น้อยที่สุดเกี่ยวกับโครงสร้างข้อมูลใด ๆ แน่นอนว่าการเข้าใช้งาน internals นั้นอันตรายน้อยกว่าเพราะไม่มีอะไรเปลี่ยนแปลงได้ แต่ผู้ใช้น้อยกว่าที่เห็นเกี่ยวกับหนึ่งโมดูล / โครงสร้างข้อมูล / แนวคิดนามธรรมใด ๆ ที่มีโอกาสมากขึ้น refactoring ฉันไม่แคร์ถ้าแผนที่เป็นต้นไม้ไบนารีที่สมดุลหรือเมาส์ในกล่องเล็ก ๆ ในคอมพิวเตอร์ของฉัน นี่คือแรงจูงใจหลักที่อยู่เบื้องหลังการซ่อนข้อมูลและใช้ได้นอก OO
Simon Bergot

12

... และอาจเป็นหนึ่งในบทความที่ OOP อ้างอิง

ไม่จริง แต่มันเพิ่มการอภิปรายโดยเฉพาะอย่างยิ่งสำหรับผู้ปฏิบัติงานที่ในเวลานั้นได้รับการฝึกฝนให้ย่อยสลายระบบโดยใช้เกณฑ์แรกที่เขาอธิบายในเอกสาร

ก่อนอื่นฉันต้องการทราบว่าการประเมินของฉันถูกต้องหรือไม่ กระบวนทัศน์ของ FP และบทความนี้ขัดแย้งกับปรัชญาหรือไม่?

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

ข้อมูลถูกส่งผ่านจากฟังก์ชั่นหนึ่งไปยังอีกฟังก์ชั่นแต่ละฟังก์ชั่นจะรับรู้ข้อมูลอย่างใกล้ชิดและ "เปลี่ยน" ไปพร้อมกัน

...ยกเว้นส่วน "ความสนิทสนม" เนื่องจากคุณสามารถ (และบ่อยครั้ง) มีฟังก์ชั่นที่ทำงานบนข้อมูลนามธรรมได้อย่างแม่นยำเพื่อหลีกเลี่ยงความใกล้ชิด ดังนั้นคุณสามารถควบคุม "ความใกล้ชิด" และคุณสามารถควบคุมมันได้ตามที่คุณต้องการโดยการตั้งค่าอินเทอร์เฟซ (เช่นฟังก์ชั่น) สำหรับสิ่งที่คุณต้องการซ่อน

ดังนั้นฉันไม่เห็นเหตุผลที่เราจะไม่สามารถปฏิบัติตามเกณฑ์การซ่อนข้อมูลของ Parnas โดยใช้การเขียนโปรแกรมการทำงานและจบลงด้วยการใช้ดัชนี KWIC พร้อมประโยชน์ที่คล้ายคลึงกันในการใช้งานครั้งที่สองของเขา

สมมติว่าพวกเขาเห็นด้วยฉันต้องการทราบว่าการนำ FPs ไปปฏิบัติใช้ของการซ่อนข้อมูลคืออะไร เห็นได้ชัดใน OOP คุณสามารถมีฟิลด์ส่วนตัวที่ไม่มีใครสามารถเข้าถึงได้ ไม่มีสิ่งใดที่เปรียบเทียบกับฉันใน FP

เท่าที่ข้อมูลมีความกังวลคุณสามารถทำอย่างละเอียดนามธรรมข้อมูลและนามธรรมชนิดข้อมูลโดยใช้ FP ใด ๆ ของโครงสร้างคอนกรีตซ่อนเร้นและการจัดการของโครงสร้างคอนกรีตเหล่านี้โดยใช้ฟังก์ชั่นเป็นนามธรรม

แก้ไข

มีการยืนยันจำนวนมากขึ้นเรื่อย ๆ ที่นี่ซึ่งระบุว่า "การซ่อนข้อมูล" ในบริบทของ FP ไม่เป็นประโยชน์ (หรือ OOP-ish (?)) ดังนั้นให้ฉันประทับตราที่นี่เป็นตัวอย่างที่ง่ายและชัดเจนจาก SICP:

สมมติว่าระบบของคุณต้องทำงานกับจำนวนตรรกยะ วิธีหนึ่งที่คุณอาจต้องการใช้แทนมันคือเป็นคู่หรือรายการของจำนวนเต็มสองตัว: ตัวเศษและส่วน ดังนั้น:

(define my-rat (cons 1 2)) ; here is my 1/2 

หากคุณไม่สนใจข้อมูลที่เป็นไปได้ว่าคุณจะได้รับเศษและส่วนที่ใช้carและcdr:

(... (car my-rat)) ; do something with the numerator

หลังจากใช้วิธีนี้ทุกส่วนของระบบที่จัดการกับจำนวนตรรกยะจะรู้ว่าจำนวนตรรกยะคือ a cons - พวกเขาจะconsสร้างตัวเลขปันส่วนและแยกพวกมันออกโดยใช้ตัวดำเนินรายการ

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

ปัญหาอีกอย่างก็คือถ้าสมมุติว่าเป็นตัวแทนที่เป็นทางเลือกสำหรับพวกเขาและคุณตัดสินใจที่จะละทิ้งการconsเป็นตัวแทน - เปลี่ยนสเกลเต็มรูปแบบอีกครั้ง

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

  • (make-rat <n> <d>)ส่งกลับจำนวนจริงที่มีเศษเป็นจำนวนเต็มและส่วนซึ่งเป็นจำนวนเต็ม<n><d>

  • (numer <x>)<x>ผลตอบแทนที่ได้เศษของจำนวนจริงที่

  • (denom <x>)<x>ผลตอบแทนส่วนของจำนวนจริงที่

และระบบจะไม่ (และไม่ควรรู้) อีกต่อไปถึงสิ่งที่ปันส่วนมา เพราะนี่คือcons, carและcdrไม่ได้อยู่ภายใน rationals แต่make-rat, numerและมีdenom แน่นอนว่านี่อาจเป็นระบบ FP ได้อย่างง่ายดาย ดังนั้น "data hiding" (ในกรณีนี้รู้จักกันดีในชื่อ data abstraction หรือความพยายามในการห่อหุ้มการแสดงและโครงสร้างคอนกรีต) มาเป็นแนวคิดที่เกี่ยวข้องและเทคนิคที่ใช้กันอย่างแพร่หลายและสำรวจไม่ว่าจะในบริบทของ OO อะไรก็ตาม

และประเด็นก็คือ ... แม้ว่าเราอาจพยายามสร้างความแตกต่างระหว่างสิ่งที่ "ซ่อนเร้น" หรือการห่อหุ้มที่พวกเขากำลังทำอยู่ (ไม่ว่าจะเป็นการซ่อนการตัดสินใจการออกแบบหรือโครงสร้างข้อมูลหรืออัลกอริทึม - ในกรณีของขั้นตอนนามธรรม) พวกเขาทั้งหมดมีรูปแบบเดียวกัน: พวกเขามีแรงจูงใจจากหนึ่งหรือหลายจุดที่ Parnas ทำไว้อย่างชัดเจน นั่นคือ:

  • ความสามารถในการเปลี่ยนแปลง: การเปลี่ยนแปลงที่จำเป็นสามารถทำได้ในพื้นที่หรือถูกแพร่กระจายผ่านระบบ
  • การพัฒนาอิสระ: ระบบสองส่วนสามารถพัฒนาได้ในระดับใด
  • ความเข้าใจ (Comprehensibility): ระบบจะต้องรู้จำนวนเท่าใดในการทำความเข้าใจส่วนใดส่วนหนึ่ง

ตัวอย่างข้างต้นถูกนำมาจากหนังสือ SICP ดังนั้นสำหรับการสนทนาแบบเต็มและนำเสนอแนวความคิดนี้ในหนังสือเล่มนี้ผมขอแนะนำให้ตรวจสอบจากบทที่ 2 ฉันยังแนะนำให้ทำความคุ้นเคยกับประเภทข้อมูลนามธรรมในบริบทของ FP ซึ่งจะนำปัญหาอื่น ๆ มาสู่ตาราง


ฉันยอมรับว่าการซ่อนข้อมูลมีความเกี่ยวข้องใน FP และเช่นเดียวกับที่คุณพูดมีวิธีการบรรลุเป้าหมายนี้
Andres F.

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

8

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

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

สามารถเห็นโครงสร้างด้านนอกสุดของข้อมูลเท่านั้น (นั่นคือรายการ) ไม่สามารถมองเห็นอะไรเกี่ยวกับข้อมูลที่มีอยู่ในรายการและสามารถทำงานกับข้อมูลผ่านฟังก์ชันเดียวที่ส่งไปให้

ฟังก์ชั่นที่ส่งผ่านเป็นอาร์กิวเมนต์ที่คล้ายคลึงกับวิธีการสาธารณะในชนิดข้อมูลที่มีในรายการ มันให้วิธีการที่ จำกัด ในการดำเนินงานกับข้อมูล แต่ไม่เปิดเผยการทำงานภายในของชนิดข้อมูล


5

ฉันจะขีดฆ่ากิ่งที่นี่และพูดว่าแนวคิดนั้นไม่เกี่ยวข้องกับ FP เหมือนกับที่เป็นใน OO

TL; DR; ประเด็นของการซ่อนข้อมูลคือเพื่อให้แน่ใจว่าความรับผิดชอบนั้นได้รับการบำรุงรักษาอย่างที่ควรเป็นและคุณไม่ได้มีนักแสดงนอกมายุ่งกับข้อมูลที่พวกเขาไม่มีความรู้ ในข้อมูล FP นั้นสร้างขึ้นโดยนิพจน์และด้วยวิธีนี้คุณไม่สามารถยุ่งกับข้อมูลได้เพราะมันไม่ใช่คุณสมบัติที่ไม่แน่นอนมากพอ ๆ กับการคำนวณแบบเรียงความซึ่งเปลี่ยนแปลงกฎของเกมโดยสิ้นเชิง


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

ความแตกต่างนี้คือใน OO โดยทั่วไปคุณจำลองสิ่งต่าง ๆ เพื่อแสดงข้อมูลของคุณ เปรียบเทียบรถบังคับ:

OO

  • คุณมี Object รถที่ซ่อนรายละเอียดเกี่ยวกับรถอย่างถูกต้องเช่นการใช้ AC (มันขับเคลื่อนด้วยสายพานหรือขับเคลื่อนด้วยแรงดันอากาศหรือไม่ผู้บริโภคไม่จำเป็นต้องรู้เพื่อซ่อนไว้)
  • รถคันนี้มีคุณสมบัติและวิธีการมากมายที่อธิบายข้อเท็จจริงทั้งหมดเกี่ยวกับรถรวมถึงวิธีการที่คุณสามารถทำงานกับรถยนต์ได้
  • วัตถุรถคันนี้มีคุณสมบัติซึ่งเป็นส่วนประกอบของรถที่ซ่อนตัวอยู่ห่างจากรถโดยรวมของการใช้งานเฉพาะของพวกเขาและข้อเท็จจริงข้อมูลของพวกเขาช่วยให้ส่วนประกอบของรถที่จะใช้แทนกันได้

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

FP

  • คุณมีการคำนวณมากมายที่ช่วยให้คุณสามารถอธิบายพฤติกรรมได้
  • การแสดงออกของพฤติกรรมเหล่านี้มีความสัมพันธ์ในลักษณะที่สามารถแปลได้ว่าพฤติกรรมของรถยนต์เกี่ยวข้องกับ eachother เช่นรถยนต์ที่มีการเร่ง / ชะลอตัวมีพฤติกรรมสองอย่างที่ต่อต้านศัตรูในลักษณะเดียวกัน

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

จำไว้ว่าช่วงเวลา LISP ซึ่งเป็นหนึ่งในภาษา FP พื้นฐานนั้นอาศัยอยู่กับชนิดข้อมูลดั้งเดิมจำนวนเล็กน้อย วิธีนี้ใช้งานได้เนื่องจากวิธีการนี้ไม่ได้เกี่ยวกับการสร้างแบบจำลองข้อมูลที่ซับซ้อนแทนการคำนวณที่สร้างและแสดงพฤติกรรมของระบบของคุณ

เมื่อฉันเริ่มเขียนโค้ดใน FP ฉันเริ่มต้นด้วยการเขียนโค้ดที่ทำอะไรบางอย่างเมื่อฉันเริ่มเขียนโค้ดใน OO ฉันเริ่มจากการเขียนแบบจำลองที่อธิบายบางอย่าง การทำสิ่งต่าง ๆ ถูกซ่อนอยู่ใน FP โดยการแสดงออกการทำสิ่งต่าง ๆ จะถูกเปิดเผยใน OO โดยการอธิบายด้วยข้อมูลซึ่งซ่อนข้อมูลนี้ไว้เพื่อ จำกัด การเปิดเผย


กลับไปที่คำถามในมือแล้ว FP พูดว่าอะไรเกี่ยวกับการซ่อนข้อมูลชื่นชมหรือไม่เห็นด้วยหรือไม่?

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


มันยอดเยี่ยมมากฉันสนุกกับการอ่านมาก ขอบคุณสำหรับการมีส่วนร่วมของคุณ
Chris McCall

5

มีความขัดแย้งเล็กน้อยที่นี่ แม้ว่าโปรแกรมการทำงานมุ่งเน้นไปที่ดีฟังก์ชั่นและบ่อยครั้งที่มีฟังก์ชั่นการทำงานที่ตรงกับประเภทข้อมูลดั้งเดิมก็มีแนวโน้มที่จะมีมากขึ้นในการซ่อนข้อมูลกว่าการเขียนโปรแกรมเชิงวัตถุ

เป็นเช่นนี้ได้อย่างไร คิดเกี่ยวกับอินเทอร์เฟซ OO ที่ดีซึ่งซ่อนข้อมูลอยู่ - บางทีอาจเป็นคอลเลกชัน (ฉันกำลังพยายามเลือกบางอย่างที่แพร่หลาย) คุณอาจไม่จำเป็นต้องรู้ชนิดของวัตถุในคอลเลกชันหรือชนิดของวัตถุที่ใช้คอลเลกชันตราบใดที่คุณรู้ว่าคอลเลกชันดำเนินการพูด IEnumerable ดังนั้นคุณมีข้อมูลที่ซ่อนอยู่

ในการเขียนโปรแกรมเชิงฟังก์ชันคุณอาจเขียนฟังก์ชันที่ทำงานกับอินเทอร์เฟซ IEnumerable ได้อย่างมีประสิทธิภาพ แต่ทำงานกับชนิดข้อมูลดั้งเดิม (หรือชนิดข้อมูลใดก็ได้) แต่ถ้าประเภทไม่เคยใช้วิธีการ IEnumerable? นี่คือกุญแจสำคัญคุณสามารถมี "วิธีการ" ที่เป็นส่วนประกอบของ "ส่วนต่อประสาน" ที่ต้องการเป็นพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชันของคุณ หรือคุณสามารถรวมฟังก์ชั่นเข้ากับข้อมูลและทำสิ่งต่าง ๆ ในแบบที่เหมือน OO

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

ดังนั้นเท่าที่ประเด็นของคุณ 1 ฉันไม่คิดว่า FP และบทความไม่เห็นด้วยจริงๆ ฉันไม่คิดว่าลักษณะของ FP ที่ไม่ซ่อนข้อมูลของคุณนั้นถูกต้อง หนึ่งสามารถใช้การออกแบบที่ผู้เขียนต้องการใน FP แน่นอน

เท่าที่จุด 4 (2 และ 3 ไม่สมเหตุสมผลที่จะตอบเนื่องจากสิ่งที่ฉันพูดไปสำหรับจุด 1) มันแตกต่างกัน นอกจากนี้ยังแตกต่างกันในภาษา OO และในเขตข้อมูลส่วนตัวหลายแห่งเป็นแบบส่วนตัวโดยการประชุมมากกว่าที่จะบังคับใช้ภาษา


ในคำอื่น ๆ : ในการเขียนโปรแกรมการทำงานมากขึ้นคือ "ซ่อน" ตามค่าเริ่มต้นเพียงเพราะมันไม่ได้อยู่! เฉพาะสิ่งที่คุณนำเข้ามาในขอบเขตอย่างชัดเจนเท่านั้นคือ "ไม่ถูกซ่อน"
leftaroundabout

3

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

ก่อนอื่นฉันต้องการทราบว่าการประเมินของฉันถูกต้องหรือไม่ กระบวนทัศน์ของ FP และบทความนี้ขัดแย้งกับปรัชญาหรือไม่?

การออกแบบ FP มุ่งเน้นไปที่การไหลของข้อมูลเป็นอย่างมาก (ซึ่ง IMHO นั้นไม่ได้แย่ขนาดนั้น หากนี่เป็น "ความขัดแย้ง" ที่สมบูรณ์ก็เถียงได้

สมมติว่าพวกเขาไม่เห็นด้วย FP จะ "ชดเชย" อย่างไรหากไม่มีการซ่อนข้อมูล บางทีพวกเขาอาจเสียสละการซ่อนข้อมูล แต่ได้รับ X, Y และ Z ฉันต้องการทราบเหตุผลว่าทำไม X, Y และ Z จึงถือว่าเป็นประโยชน์มากกว่าการซ่อนข้อมูล

IMHO มันไม่ได้ชดเชย ดูด้านล่าง

หรือสมมติว่าพวกเขาไม่เห็นด้วย FP อาจรู้สึกว่าการซ่อนข้อมูลไม่ดี ถ้าเป็นเช่นนั้นทำไมจึงคิดว่าการซ่อนข้อมูลไม่ดี

ฉันไม่คิดว่าผู้ใช้หรือนักออกแบบ FP ส่วนใหญ่รู้สึกหรือคิดด้วยวิธีนี้ดูด้านล่าง

สมมติว่าพวกเขาเห็นด้วยฉันต้องการทราบว่าการนำ FPs ไปปฏิบัติใช้ของการซ่อนข้อมูลคืออะไร เห็นได้ชัดใน OOP คุณสามารถมีฟิลด์ส่วนตัวที่ไม่มีใครสามารถเข้าถึงได้ ไม่มีสิ่งใดที่เปรียบเทียบกับฉันใน FP

นี่คือประเด็น - คุณอาจเคยเห็นระบบ OOP มากมายที่ใช้งานในลักษณะที่ไม่สามารถใช้งานได้ซึ่งคุณเชื่อว่า OOP นั้นใช้งานไม่ได้ และนั่นคือการเข้าใจผิด IMHO OOP และ FP เป็นแนวคิดแบบ orthogonal เป็นส่วนใหญ่และคุณสามารถสร้างระบบ OO ที่ใช้งานได้อย่างสมบูรณ์แบบซึ่งให้คำตอบที่ชัดเจนสำหรับคำถาม การใช้งาน "วัตถุ" แบบคลาสสิกใน FP ทำได้โดยใช้การปิดและถ้าคุณต้องการให้วัตถุถูกนำมาใช้ในระบบการทำงานจุดสำคัญคือการออกแบบให้ไม่เปลี่ยนรูป

ดังนั้นสำหรับการสร้างระบบที่ใหญ่ขึ้น IMHO คุณสามารถสร้างโมดูลคลาสและวัตถุโดยใช้แนวคิด OO ตามวิธีที่อธิบายไว้ภายใต้ "Modularization 2" ในบทความโดยไม่ต้องออกจาก "เส้นทาง FP" คุณจะใช้แนวคิดโมดูลของภาษา FP ที่คุณชื่นชอบทำให้วัตถุทั้งหมดของคุณไม่เปลี่ยนรูปและใช้ "ดีที่สุดของทั้งสองโลก"


3

TL; DR : ไม่

กระบวนทัศน์ของ FP และบทความนี้ขัดแย้งกับปรัชญาหรือไม่?

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

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

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

การซ่อนข้อมูล

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

3
"การเขียนโปรแกรมฟังก์ชั่นไม่ได้มีการปิดบังข้อมูลดังนั้นจึงไม่จำเป็นต้องปิดบังข้อมูลมากนัก" - นี่เป็นการยืนยันที่ทำให้เข้าใจผิดมาก คุณพูดว่าตัวเอง (และฉันเห็นด้วย) ว่าสาเหตุหนึ่งที่ทำให้พฤติกรรมห่อหุ้มคือการควบคุมการกลายพันธุ์ของข้อมูล แต่เพื่อสรุปว่าการขาดการกลายพันธุ์เกือบจะทำให้การห่อหุ้มนั้นไร้ประโยชน์นั้นเป็นสิ่งที่ยืดเยื้อ ADTs และ data abstraction โดยทั่วไปนั้นแพร่หลายใน FP และวรรณกรรม
Thiago Silva

ฉันไม่เคยพูดว่า "เกือบห่อหุ้มห่อตัวไร้ประโยชน์" นั่นคือความคิดของคุณและของคุณคนเดียว ฉันบอกว่าคุณไม่จำเป็นต้องซ่อนข้อมูลมากนักเนื่องจากขาดการกลายพันธุ์ของตัวแปร นี่ไม่ได้ทำให้การห่อหุ้มหรือซ่อนข้อมูลไร้ประโยชน์มันแค่ลดการใช้เพราะกรณีเหล่านั้นไม่มีอยู่ ส่วนกรณีอื่น ๆ ที่การซ่อนและห่อหุ้มข้อมูลมีประโยชน์ก็ยังคงใช้ได้
dietbuddha
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.