Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

การเขียนโปรแกรมฟังก์ชั่นใน Ruby (คู่มือฉบับสมบูรณ์)

บางทีคุณอาจเพิ่งเคยได้ยินเกี่ยวกับ Functional Programming และมีคำถามบางอย่าง

ชอบ…

  • การเขียนโปรแกรมเชิงฟังก์ชันคืออะไรกันแน่?
  • เปรียบเทียบกับการเขียนโปรแกรมเชิงวัตถุเป็นอย่างไร
  • คุณควรใช้การเขียนโปรแกรมเชิงฟังก์ชันใน Ruby หรือไม่

ให้ฉันตอบคำถามเหล่านี้ให้คุณเพื่อให้คุณได้รับแนวคิดที่ดีขึ้นเกี่ยวกับวิธีการทำงาน

ฟังก์ชั่นการเขียนโปรแกรมคืออะไร

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

และแนวคิดพื้นฐานเบื้องหลังกระบวนทัศน์นี้เข้าใจง่ายกว่าที่คุณคิด

ในการเขียนโปรแกรมเชิงฟังก์ชัน เรา หลีกเลี่ยงการเปลี่ยนสถานะ และเราพยายามเขียน ฟังก์ชันที่ "บริสุทธิ์" .

การหลีกเลี่ยงการเปลี่ยนแปลงสถานะหมายความว่าฟังก์ชันเหล่านี้จะไม่เปลี่ยนแปลงสิ่งใดนอกฟังก์ชัน ไม่มีตัวแปรอินสแตนซ์ ไม่เปลี่ยนแปลงวัตถุที่ส่งผ่านเข้ามา...

ไม่มีเลย!

ในภาษาการเขียนโปรแกรมที่ใช้งานได้ (เช่น Haskell) ข้อมูลทั้งหมดจะไม่เปลี่ยนแปลง

มีบางอย่างเช่นตัวแปร แต่มีพฤติกรรมเหมือนในโลกคณิตศาสตร์ เมื่อกำหนดค่าตัวแปรแล้ว คอมไพเลอร์จะไม่อนุญาตให้คุณกำหนดตัวแปรนี้ใหม่ด้วยค่าอื่น

การเขียนโปรแกรมฟังก์ชั่นใน Ruby (คู่มือฉบับสมบูรณ์)

ประโยชน์ของการเขียนโปรแกรมเชิงฟังก์ชัน

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

ตัวอย่าง :

def all_different_from_first?(arr)
  first = arr.shift

  arr.all? { |n| n != first }
end

arr = [1,3,5,7,9]

p all_different_from_first?(arr)
# true

ในตัวอย่างนี้ ฉันต้องการค้นหาว่าองค์ประกอบทั้งหมดในอาร์เรย์แตกต่างจากองค์ประกอบแรกหรือไม่

ในการทำงานนี้ เราจำเป็นต้องลบองค์ประกอบแรกออกจากอาร์เรย์ &ในเวลาเดียวกันให้บันทึกองค์ประกอบนี้ เพื่อที่เราจะสามารถเปรียบเทียบกับส่วนที่เหลือได้

เราจะทำอย่างนั้นได้อย่างไร

เรากำลังทำงานกับอาร์เรย์ &หากคุณดูรายการวิธีการที่มีอยู่ คุณจะพบว่าวิธี Array#shift ทำในสิ่งที่เราต้องการได้อย่างแท้จริง

มันใช้งานได้ดีจนถึง…

…คุณดูค่าของ arr หลังจากเรียกใช้เมธอดหนึ่งครั้ง:

all_different_from_first?(arr)
# true

arr
# [3,5,7,9]

เซอร์ไพรส์!

อาร์เรย์สูญเสียหนึ่งองค์ประกอบ (1 ) และเราไม่ได้สังเกต

บั๊กที่เปลี่ยนแปลงได้แบบนี้จะหลอกล่อได้

เวอร์ชันคงที่ :

def all_different_from_first?(arr)
  arr[1..-1].all? { |n| n != arr.first }
end

การทำงานเทียบกับ OOP

เราทุกคนควรใช้โปรแกรมเชิงฟังก์ชันหรือไม่

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

ไม่เลย ไม่จำเป็นต้องเร่งรีบและลงโปรแกรมฟังก์ชันเต็มรูปแบบ Ruby ออกแบบมาสำหรับ OOP ดังนั้นคุณจะต้องต่อสู้กับธัญพืช

ข่าวดี :

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

มาพูดถึงวิธีการทำกัน

ลดการกลายพันธุ์ให้มากที่สุด

วิธีหนึ่งที่ทำได้คือหยุดใช้ attr_accessor ติดเฉพาะ attr_reader .

หลังจากที่คุณทำเช่นนั้น คุณจะต้องคอยจับตาดูสตริง อาร์เรย์ และแฮช

มีวิธีการที่จะเปลี่ยนวัตถุเหล่านี้:

  • วิธีการส่วนใหญ่ที่ลงท้ายด้วย ! (เช่น gsub! )
  • ลบ
  • อัพเดท
  • ชัดเจน
  • เปลี่ยน / ไม่เปลี่ยน / ป๊อป / กด

ขั้นตอนแรกคือการตระหนักถึงวิธีการเหล่านี้

ถ้าคุณต้องใช้หนึ่งในวิธีการเหล่านี้ คุณสามารถทำงานกับวัตถุที่ซ้ำกัน

กำหนดสตริงและโคลนของสตริงนั้น :

str = "abcd"
dup = str.dup

เราจะได้ผลลัพธ์เหล่านี้เมื่อเราclear สตริงที่ซ้ำกัน:

dup.clear

# str => "abcd"
# dup => ""

ซึ่งจะทำให้สตริงเดิมปลอดภัย

การสมัครบางส่วน

การเขียนโปรแกรมเชิงฟังก์ชันมีมากกว่าข้อมูลที่ไม่เปลี่ยนรูปและฟังก์ชันบริสุทธิ์

เช่นเดียวกับการใช้งานฟังก์ชันบางส่วน หรือที่เรียกว่า “currying”

ตัวอย่าง :

def add(a,b)
  a + b
end

add_five = method(:add).curry[5]

add_five.call(5)
# 10

add_five.call(20)
# 25

สังเกตว่า add วิธีรับสองอาร์กิวเมนต์ แต่โดยใช้ curry วิธีที่เราสามารถ "โหลดล่วงหน้า" หนึ่งในอาร์กิวเมนต์ได้

จากนั้นเราจะได้แลมบ์ดาที่เราเรียกได้โดยใช้อาร์กิวเมนต์ที่ 2

นี่เป็นอีกตัวอย่างหนึ่ง :

list = (1..10)

greater_than = ->(x,y) { y > x }.curry

list.select(&greater_than.(5))
# [6, 7, 8, 9, 10]

list.select(&greater_than.(8))
# [9, 10]

อีกหนึ่งตัวอย่าง :

divisible_by = ->(x,y) { y % x == 0 }.curry

list.select(&divisible_by.(5))
# [5, 10]

list.select(&divisible_by.(2))
# [2, 4, 6, 8, 10]

สรุป

คุณได้เรียนรู้เกี่ยวกับ Functional Programming ที่สำคัญคือฟังก์ชันล้วนๆ และข้อมูลที่ไม่เปลี่ยนรูป เป็นเพียงวิธีคิดเกี่ยวกับโค้ดของคุณและไม่เข้ากันกับ OOP โดยสิ้นเชิง

ขอบคุณที่เข้ามาอ่าน อย่าลืมสมัครรับจดหมายข่าวหากยังไม่ได้สมัคร! 🙂