ZuriHac: ฝึกการเขียนโปรแกรมเชิงฟังก์ชัน

ในเดือนมิถุนายนของปีนี้ ในเมืองเล็กๆ ของสวิสอย่าง Rapperswil มีงานที่เรียกว่า ซูริแฮค- ครั้งนี้ได้รวบรวมผู้ชื่นชอบ Haskell มากกว่าห้าร้อยคน ตั้งแต่ผู้เริ่มต้นจนถึงผู้ก่อตั้งภาษา แม้ว่าผู้จัดงานจะเรียกกิจกรรมนี้ว่า Hackathon แต่ก็ไม่ใช่การประชุมหรือ Hackathon ในแง่คลาสสิก รูปแบบของมันแตกต่างจากโปรแกรมเมอร์ทั่วไป เราได้เรียนรู้เกี่ยวกับ ZuriHac โดยโชคดี และมีส่วนร่วม และตอนนี้เราถือว่าเป็นหน้าที่ของเราที่จะต้องบอกเล่าเกี่ยวกับการค้นพบที่ไม่ธรรมดานี้!

ZuriHac: ฝึกการเขียนโปรแกรมเชิงฟังก์ชัน

เกี่ยวกับเรา

บทความนี้จัดทำโดยนักศึกษาชั้นปีที่ 3 สองคนของโปรแกรม "คณิตศาสตร์ประยุกต์และสารสนเทศ" ที่ National Research University Higher School of Economics - เซนต์ปีเตอร์สเบิร์ก: Vasily Alferov และ Elizaveta Vasilenko ความหลงใหลในการเขียนโปรแกรมเชิงฟังก์ชันสำหรับเราทั้งคู่เริ่มต้นจากการบรรยายโดย D. N. Moskvin ในปีที่ 2 ของมหาวิทยาลัย ปัจจุบัน Vasily กำลังเข้าร่วมในโปรแกรม Google Summer of Code ซึ่งเขากำลังใช้กราฟพีชคณิตใน Haskell ภายใต้การแนะนำของทีมงานโครงการ สาหร่าย- Elizaveta ใช้ทักษะการเขียนโปรแกรมเชิงฟังก์ชันที่ได้รับในงานหลักสูตรที่อุทิศให้กับการนำอัลกอริธึมต่อต้านการรวมเข้าด้วยกันพร้อมกับการประยุกต์ใช้ในทฤษฎีประเภทในภายหลัง

รูปแบบกิจกรรม

กลุ่มเป้าหมายคือเจ้าของโครงการโอเพ่นซอร์ส โปรแกรมเมอร์ที่ต้องการมีส่วนร่วมในการพัฒนา นักวิจัยการเขียนโปรแกรมเชิงฟังก์ชัน และผู้ที่สนใจ Haskell ในปีนี้ นักพัฒนาจากโครงการโอเพ่นซอร์ส Haskell มากกว่าห้าสิบโครงการจากทั่วโลกมารวมตัวกันที่ HSR Hochschule für Technik Rapperswil เพื่อพูดคุยเกี่ยวกับผลิตภัณฑ์ของตนและดึงดูดผู้คนหน้าใหม่ที่สนใจในการพัฒนาของพวกเขา

ZuriHac: ฝึกการเขียนโปรแกรมเชิงฟังก์ชัน

รูปภาพจากทวิตเตอร์ ซูริแฮค

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

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

นอกจากการปฏิบัติที่มีคุณค่าแล้ว ZuriHac ยังมีการบรรยายและชั้นเรียนปริญญาโทอีกหลายรายการอีกด้วย เราจำการบรรยายสองครั้งเป็นพิเศษ ในตอนแรก Andrey Mokhov จากมหาวิทยาลัยนิวคาสเซิลพูดถึง Selective Application Functors ซึ่งเป็นคลาสประเภทที่ควรกลายเป็นสื่อกลางระหว่าง Applicative Functors และ Monads ในการบรรยายอื่น Simon Peyton Jones หนึ่งในผู้ก่อตั้ง Haskell พูดคุยเกี่ยวกับวิธีการทำงานของการอนุมานประเภทในคอมไพเลอร์ GHC

ZuriHac: ฝึกการเขียนโปรแกรมเชิงฟังก์ชัน

บรรยายโดย ไซมอน เพย์ตัน โจนส์ รูปภาพจากทวิตเตอร์ ซูริแฮค

มาสเตอร์คลาสที่จัดขึ้นระหว่างแฮ็กกาธอนนั้นแบ่งออกเป็น 3 ประเภทขึ้นอยู่กับระดับการฝึกอบรมของผู้เข้าร่วม งานที่เสนอให้กับผู้เข้าร่วมที่เข้าร่วมการพัฒนาโครงการก็มีระดับความยากเช่นกัน ชุมชนโปรแกรมเมอร์เชิงฟังก์ชันเล็กๆ แต่เป็นมิตร ยินดีต้อนรับผู้มาใหม่เข้าสู่ตำแหน่งของตนอย่างมีความสุข อย่างไรก็ตาม เพื่อให้เข้าใจการบรรยายของ Andrei Mokhov และ Simon Peyton Jones หลักสูตรการเขียนโปรแกรมเชิงฟังก์ชันที่เราเรียนที่มหาวิทยาลัยมีประโยชน์มาก

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

และตอนนี้เราจะพูดถึงโครงการในการพัฒนาที่เราเข้าร่วม

Pandoc

Pandoc เป็นตัวแปลงเอกสารข้อความสากลจากทุกรูปแบบไปเป็นรูปแบบใดก็ได้ ตัวอย่างเช่น จาก docx เป็น pdf หรือจาก Markdown ถึง MediaWiki ผู้เขียนคือ John MacFarlane เป็นศาสตราจารย์ด้านปรัชญาที่มหาวิทยาลัยแคลิฟอร์เนีย เบิร์กลีย์ โดยทั่วไปแล้ว Pandoc ค่อนข้างมีชื่อเสียง และเพื่อนของเราบางคนก็ประหลาดใจเมื่อรู้ว่า Pandoc เขียนด้วยภาษา Haskell

ZuriHac: ฝึกการเขียนโปรแกรมเชิงฟังก์ชัน

รายการรูปแบบเอกสารที่ Pandoc รองรับ นอกจากนี้ยังมีกราฟทั้งหมดบนไซต์ แต่รูปภาพนี้ไม่เหมาะกับบทความ

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

$ cat example.html
<h1>Hello, World!</h1>

$ pandoc -f html -t native example.html
[Header 1 ("hello-world",[],[]) [Str "Hello,",Space,Str "World!"]]

ผู้อ่านที่เคยร่วมงานกับ Haskell อย่างน้อยก็สามารถสันนิษฐานได้จากตัวอย่างเล็ก ๆ นี้ว่า Pandoc เขียนด้วย Haskell: ผลลัพธ์ของคำสั่งนี้คือการแสดงสตริงของโครงสร้างภายในของ Pandoc ซึ่งสร้างขึ้นในลักษณะที่มักจะทำ ใน Haskell เช่นในไลบรารีมาตรฐาน

ดังนั้น คุณจะเห็นได้ว่าการแสดงภายในเป็นโครงสร้างแบบเรียกซ้ำ ในแต่ละโหนดภายในซึ่งมีรายการอยู่ ตัวอย่างเช่น ที่ระดับบนสุดจะมีรายการหนึ่งองค์ประกอบ - ส่วนหัวระดับแรกที่มีแอตทริบิวต์ "hello-world",[],[] ที่ซ่อนอยู่ภายในส่วนหัวนี้คือรายการสตริง “Hello” ตามด้วยช่องว่างและสตริง “World!”

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

หากเราลงไปถึงระดับการใช้งาน ประเภทข้อมูลสำหรับเอกสารทั้งหมดจะถูกกำหนดดังนี้:

data Pandoc = Pandoc Meta [Block]

Here Block คือจุดยอดภายในที่กล่าวถึงข้างต้น และ Meta คือข้อมูลเกี่ยวกับเอกสาร เช่น ชื่อเรื่อง วันที่สร้าง ผู้เขียน ซึ่งแตกต่างกันสำหรับรูปแบบที่แตกต่างกัน และหากเป็นไปได้ Pandoc จะพยายามรักษาข้อมูลดังกล่าวไว้เมื่อแปลจากรูปแบบเป็น รูปแบบ.

ตัวสร้างประเภทบล็อกเกือบทั้งหมด - ตัวอย่างเช่นส่วนหัวหรือพารา (ย่อหน้า) - รับแอตทริบิวต์และรายการจุดยอดระดับล่างเป็นอาร์กิวเมนต์ - แบบอินไลน์ตามกฎ ตัวอย่างเช่น Space หรือ Str เป็นตัวสร้างประเภท Inline และแท็ก HTML ก็เปลี่ยนเป็น Inline พิเศษของตัวเองด้วย เราไม่เห็นว่ามีประโยชน์ในการให้คำจำกัดความที่สมบูรณ์ของประเภทเหล่านี้ แต่โปรดทราบว่าสามารถพบได้ที่นี่ ที่นี่.

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

เมื่อแปลง เช่น จาก LaTeX เป็น HTML ขั้นแรกโมดูลพิเศษที่เรียกว่า LaTeXReader จะแปลงเอกสารอินพุตเป็น AST จากนั้นอีกโมดูลหนึ่งที่เรียกว่า HTMLWriter จะแปลง AST เป็น HTML ด้วยสถาปัตยกรรมนี้ ไม่จำเป็นต้องเขียนการแปลงเป็นจำนวนกำลังสอง - แค่เขียน Reader และ Writer สำหรับแต่ละรูปแบบใหม่ก็เพียงพอแล้ว และคู่การแปลงที่เป็นไปได้ทั้งหมดจะได้รับการสนับสนุนโดยอัตโนมัติ

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

ภาษา Haskell ได้รับเลือกไม่เพียงเพราะผู้แต่งชื่นชอบการเขียนโปรแกรมเชิงฟังก์ชันเท่านั้น Haskell มีชื่อเสียงในด้านความสามารถในการประมวลผลข้อความที่กว้างขวาง ตัวอย่างหนึ่งคือห้องสมุด พาร์เซก เป็นไลบรารีที่ใช้แนวคิดการเขียนโปรแกรมเชิงฟังก์ชันอย่างแข็งขัน - monoids, monads, applicative และฟังก์ชันทางเลือก - เพื่อเขียน parsers โดยพลการ มองเห็นพลังอันเต็มเปี่ยมของพาร์เซกได้ ตัวอย่าง จาก HaskellWiki โดยที่ตัวแยกวิเคราะห์ที่สมบูรณ์ของภาษาการเขียนโปรแกรมที่จำเป็นอย่างง่ายจะถูกแยกวิเคราะห์ แน่นอนว่า Parsec ยังถูกใช้อย่างแข็งขันใน Pandoc อีกด้วย

อธิบายโดยย่อว่า monads ใช้สำหรับการแยกวิเคราะห์ตามลำดับ เมื่อสิ่งหนึ่งมาถึงก่อน แล้วจึงตามมาด้วยอีกสิ่งหนึ่ง ตัวอย่างเช่น ในตัวอย่างนี้:

whileParser :: Parser Stmt
whileParser = whiteSpace >> statement

ก่อนอื่นคุณต้องนับช่องว่างก่อน จากนั้นจึงตามด้วยคำสั่ง ซึ่งมีประเภท Parser Stmt ด้วย

ฟังก์ชันทางเลือกจะใช้ในการย้อนกลับหากการแยกวิเคราะห์ล้มเหลว ตัวอย่างเช่น,

statement :: Parser Stmt
statement = parens statement <|> sequenceOfStmt

หมายความว่าคุณต้องพยายามอ่านข้อความในวงเล็บ หรือพยายามอ่านข้อความหลายๆ ข้อความตามลำดับ

Applicative functors ถูกใช้เป็นทางลัดสำหรับ monads เป็นหลัก ตัวอย่างเช่น ให้ฟังก์ชัน tok อ่านโทเค็นบางส่วน (นี่คือฟังก์ชันจริงจาก LaTeXReader) ลองดูที่ชุดค่าผสมนี้

const <$> tok <*> tok

มันจะอ่านโทเค็นสองอันติดต่อกันและส่งคืนโทเค็นแรก

สำหรับคลาสทั้งหมดนี้ Haskell มีตัวดำเนินการสัญลักษณ์ที่สวยงาม ซึ่งทำให้การเขียนโปรแกรม Reader ดูเหมือนศิลปะ ASCII เพียงแค่ชื่นชมรหัสที่ยอดเยี่ยมนี้

งานของเราเกี่ยวข้องกับ LaTeXReader งานของ Vasily คือการสนับสนุนคำสั่ง mbox และ hbox ซึ่งมีประโยชน์สำหรับการเขียนแพ็คเกจใน LaTeX Elizabeth มีหน้าที่รับผิดชอบในการสนับสนุนคำสั่ง epigraph ซึ่งช่วยให้คุณสร้าง epigraphs ในเอกสาร LaTeX ได้

ฮาเทรซ

ระบบปฏิบัติการที่คล้ายกับ UNIX มักจะใช้การเรียกระบบ ptrace มีประโยชน์ในการดีบักและจำลองสภาพแวดล้อมของโปรแกรม ทำให้คุณสามารถติดตามการเรียกของระบบที่โปรแกรมทำ ตัวอย่างเช่น ยูทิลิตี strace ที่มีประโยชน์มากใช้ ptrace ภายใน

Hatrace เป็นไลบรารีที่ให้อินเทอร์เฟซสำหรับ ptrace ใน Haskell ความจริงก็คือ ptrace นั้นมีความซับซ้อนมากและเป็นการยากที่จะใช้โดยตรง โดยเฉพาะจากภาษาที่ใช้งานได้

Hatrace ทำงานเหมือน strace เมื่อเริ่มต้นและยอมรับข้อโต้แย้งที่คล้ายกัน มันแตกต่างจาก strace ตรงที่เป็นไลบรารีที่มีอินเทอร์เฟซที่เรียบง่ายกว่าแค่ ptrace

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

เราได้เพิ่มอินเทอร์เฟซการเรียกระบบลงในไลบรารี - Elizaveta เพิ่ม brk และ Vasily เพิ่ม mmap จากผลงานของเรา คุณสามารถใช้อาร์กิวเมนต์ของการเรียกระบบเหล่านี้ได้ง่ายและแม่นยำยิ่งขึ้นเมื่อใช้ไลบรารี

ที่มา: will.com

เพิ่มความคิดเห็น