ภาษาที่ใช้งานได้จริงจัดการกับส่วนย่อยได้อย่างไร


23

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

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

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


1
ทำไมคุณคิดว่าฟังก์ชั่นไม่ได้หมายถึงคลาส? บางส่วนของชั้นเรียนเฟิมาจากเสียงกระเพื่อม - CLOS ดูที่ Clojure namespacesและประเภทหรือโมดูลและHaskell

ฉันพูดถึงภาษาที่ใช้งานได้ซึ่งไม่ได้มีชั้นเรียนฉันตระหนักดีถึงบางส่วนที่ไม่ดี
กาแฟไฟฟ้า

1
ยกตัวอย่าง Caml ภาษาน้องสาวของ OCaml เพิ่มวัตถุ แต่ Caml เองก็ไม่มี
กาแฟไฟฟ้า

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

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

คำตอบ:


19

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

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

OTOH, Haskell และตระกูล ML มีระบบโมดูลที่ชัดเจน

การวางแนววัตถุเป็นเรื่องเกี่ยวกับข้อมูลที่เป็นนามธรรม แค่นั้นแหละ. Modularity, Inheritance, Polymorphism หรือแม้แต่สถานะที่เปลี่ยนแปลงได้นั้นเป็นความกังวลแบบมุมฉาก


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

Sidenote - โมดูลและหน่วยเป็นโครงสร้างสองแบบที่แตกต่างกันใน Racket - โมดูลเทียบได้กับเนมสเปซ เอกสารจะมีรายละเอียดมากขึ้นเกี่ยวกับความแตกต่าง
Jack

@Jack: moduleผมไม่ทราบว่าไม้นอกจากนี้ยังมีแนวคิดที่เรียกว่า ฉันคิดว่ามันเป็นโชคร้ายที่ไม้มีแนวคิดที่เรียกว่าmoduleที่ไม่ได้เป็นโมดูลและแนวคิดที่เป็นโมดูล moduleแต่ไม่เรียกว่า อย่างไรก็ตามคุณเขียน: "หน่วยเป็นครึ่งทางระหว่างเนมสเปซและอินเตอร์เฟส OO" ทีนี้นิยามของโมดูลนั้นไม่ใช่อะไร?
Jörg W Mittag

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

4

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

ในภาษา OO คุณมักจะให้ความสนใจกับคำนาม "สัตว์", "mailserver", "fork fork ของเขา" ฯลฯ ภาษาที่ใช้งานได้ในทางตรงข้ามเน้นคำกริยา "to walk", "to mail" , "เป็นกระทุ้ง" ฯลฯ

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

อีกตัวอย่างที่ชัดเจนของโครงการนี้คือโครงการที่ฉันทำงานเมื่อไม่นานมานี้ ฉันกำลังเขียนฐานข้อมูลใน Haskell ฉันมีหนึ่ง 'ภาษาที่ฝังตัว' เพื่อระบุการดำเนินการในระดับต่ำสุด; เช่นอนุญาตให้ฉันเขียนและอ่านสิ่งต่าง ๆ จากสื่อบันทึกข้อมูล ฉันมีอีกภาษาหนึ่งแยกจากกัน 'ภาษาที่ฝัง' เพื่อระบุการดำเนินการในระดับสูงสุด ถ้าอย่างนั้นฉันก็มีล่ามแปลว่าการดำเนินงานจากระดับที่สูงขึ้นไปเป็นระดับล่างคืออะไร

นี่เป็นรูปแบบทั่วไปที่น่าทึ่งของนามธรรม แต่มันไม่ได้เป็นเพียงหนึ่งเดียวที่มีอยู่ในภาษาการทำงาน


4

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

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

ความแตกต่างที่โดดเด่นที่สุดระหว่าง OOP และ FP wrt modularity คือการเริ่มต้น "หน่วย" ในการรวมกลุ่ม OOP ด้วยกันเป็นวัตถุการดำเนินการต่างๆในกรณีเดียวกันของค่าในขณะที่ "หน่วย" เริ่มต้นในการรวมกลุ่ม FP เข้าด้วยกันเป็นฟังก์ชั่นการดำเนินงานเดียวกันสำหรับกรณีต่างๆ ใน FP มันยังง่ายมากที่จะรวมการดำเนินการเข้าด้วยกันเช่นโมดูล (BTW ไม่ใช่ Haskell หรือ F # มีระบบโมดูล ML แบบเต็มเปี่ยม) ปัญหาการแสดงออกเป็นหน้าที่ของการเพิ่มทั้งการดำเนินการใหม่ที่ทำงานกับค่าทั้งหมด (เช่นการแนบวิธีการใหม่ไปยังวัตถุที่มีอยู่) และกรณีใหม่ของค่าที่การดำเนินการทั้งหมดควรสนับสนุน (เช่นการเพิ่มคลาสใหม่ด้วยอินเทอร์เฟซเดียวกัน) ตามที่กล่าวไว้ในการบรรยายครั้งแรกของ Ralf Laemmel ด้านล่าง (ซึ่งมีตัวอย่างมากมายใน C #) การเพิ่มการปฏิบัติการใหม่เป็นปัญหาในภาษา OOP

การรวมกันของ OOP และ FP ใน Scala อาจทำให้มันเป็นหนึ่งในภาษาที่ทรงพลังที่สุด wrt ต้นแบบ แต่ OCaml ยังคงเป็นภาษาที่ฉันชอบและในความคิดเห็นส่วนตัวของฉันมันไม่ได้ขาดแค่สกาล่า การบรรยายสองครั้งของ Ralf Laemmel ด้านล่างหารือเกี่ยวกับการแก้ปัญหาการแสดงออกใน Haskell ฉันคิดว่าวิธีนี้แม้จะใช้งานได้ดี แต่มันก็ยากที่จะใช้ข้อมูลที่ได้ด้วยพาราเมตริก การแก้ปัญหาการแสดงออกด้วยตัวแปรหลากหลายใน OCaml ซึ่งอธิบายไว้ในบทความ Jaques Garrigue ที่ลิงก์ด้านล่างไม่มีข้อบกพร่องนี้ ฉันยังเชื่อมโยงไปยังบทตำราที่เปรียบเทียบการใช้โมดูลาร์ที่ไม่ใช่ OOP และ OOP ใน OCaml

ด้านล่างนี้คือลิงก์เฉพาะของ Haskell และ OCaml ซึ่งขยายตัวในปัญหานิพจน์ :


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

2
ฉันเพิ่งให้คำตอบจริงมากกว่าแค่ลิงก์เพื่อแก้ไข
lukstafi

0

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

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

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

นำAnimalตัวอย่างของคุณมาพิจารณาใช้ฟีดฟีด การใช้งาน OOP ที่ตรงไปตรงมาคือการรักษาชุดของAnimalวัตถุและวนรอบวัตถุทั้งหมดเรียกfeedวิธีการในแต่ละวัตถุ

อย่างไรก็ตามสิ่งต่าง ๆ จะยุ่งยากเมื่อคุณลงรายละเอียด Animalวัตถุธรรมชาติที่รู้ว่าสิ่งที่ชนิดของอาหารมันกินและวิธีการมากที่จะต้องเพื่อที่จะรู้สึกเต็ม มันไม่ได้รู้ว่าอาหารถูกเก็บไว้ที่ใดและมีจำนวนเท่าใดดังนั้นFoodStoreวัตถุจึงกลายเป็นที่พึ่งของทุกคนAnimalไม่ว่าจะเป็นสนามของAnimalวัตถุหรือส่งผ่านเป็นพารามิเตอร์ของfeedวิธีการ อีกทางหนึ่งเพื่อให้Animalชั้นเรียนมีความเหนียวแน่นมากขึ้นคุณอาจย้ายfeed(animal)ไปที่FoodStoreวัตถุหรือคุณอาจสร้างสิ่งที่น่ารังเกียจในชั้นเรียนที่เรียกว่าAnimalFeederหรือบางอย่าง

ใน FP ไม่มีความชอบสำหรับเขตข้อมูลของAnimalที่จะอยู่รวมกลุ่มกันเสมอซึ่งมีผลกระทบที่น่าสนใจสำหรับการใช้ซ้ำ สมมติว่าคุณมีรายการAnimalระเบียนที่มีเขตข้อมูลชอบname, species, location, food type, food amountฯลฯ นอกจากนี้คุณยังมีรายชื่อของFoodStoreระเบียนที่มีสาขาเหมือนlocation, และfood typefood amount

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

คุณท้ายด้วยฟังก์ชั่นมากมายที่ทำสิ่งที่มีประโยชน์ด้วย[(Num A, Eq B)]ที่นำมาใช้ใหม่และแบบแยกส่วน แต่คุณมีปัญหาในการหาตำแหน่งที่จะวางหรือสิ่งที่เรียกว่าเป็นกลุ่ม ผลที่ได้คือโมดูล FP นั้นแยกได้ยากกว่า แต่การจำแนกประเภทมีความสำคัญน้อยกว่ามาก


-1

หนึ่งในโซลูชันที่ได้รับความนิยมคือการแบ่งรหัสออกเป็นโมดูลนี่คือวิธีที่มันทำใน JavaScript:

    media.podcast = (function(name) {
    var fileExtension = 'mp3';        

     function determineFileExtension() {
         console.log('File extension is of type ' + fileExtension);
     }

     return {
         download: function(episode) {
            console.log('Downloading ' + episode + ' of ' + name);
            determineFileExtension();
        }
    }    
}('Astronomy podcast'));

บทความเต็มอธิบายรูปแบบนี้ใน JavaScriptนอกเหนือจากที่มีจำนวนของวิธีการอื่น ๆ เพื่อกำหนดโมดูลเช่นRequireJS , CommonJS , Google ปิด อีกตัวอย่างหนึ่งคือ Erlang ที่คุณมีทั้งโมดูลและพฤติกรรมที่บังคับใช้ API และรูปแบบมีบทบาทคล้ายกับส่วนต่อประสานใน OOP

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