เหตุใดจึงมีฟังก์ชั่นสองประเภทในยาอายุวัฒนะ?


279

ฉันเรียนรู้ยาอายุวัฒนะและสงสัยว่าทำไมมันมีนิยามของฟังก์ชันสองประเภท:

  • ฟังก์ชั่นที่กำหนดไว้ในโมดูลด้วยdefเรียกว่าการใช้myfunction(param1, param2)
  • ฟังก์ชั่นไม่ระบุชื่อที่กำหนดด้วยfnเรียกว่าใช้myfn.(param1, param2)

มีเพียงฟังก์ชันประเภทที่สองที่ดูเหมือนเป็นวัตถุชั้นหนึ่งและสามารถส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันอื่นได้ fnฟังก์ชั่นที่กำหนดไว้ในความต้องการโมดูลที่จะห่อใน มีน้ำตาลซินแทคติคที่ดูเหมือนotherfunction(myfunction(&1, &2))จะทำให้ง่าย แต่ทำไมมันจำเป็นในตอนแรก? ทำไมเราทำotherfunction(myfunction))ไม่ได้? มันเป็นเพียงเพื่อให้ฟังก์ชั่นการโทรโมดูลโดยไม่ต้องวงเล็บเช่นในทับทิม? ดูเหมือนว่าจะมีการสืบทอดคุณสมบัตินี้จาก Erlang ซึ่งมีฟังก์ชั่นโมดูลและฟังก์ชั่นสนุกด้วยเช่นกันจริง ๆ แล้วมันมาจากวิธีที่ Erlang VM ทำงานภายในหรือไม่

มันมีประโยชน์อะไรบ้างที่มีฟังก์ชั่นสองประเภทและแปลงจากประเภทหนึ่งไปเป็นอีกประเภทหนึ่งเพื่อส่งผ่านไปยังหน้าที่อื่น ๆ ? มีประโยชน์ไหมที่มีเครื่องหมายสองแบบที่แตกต่างกันในการเรียกใช้ฟังก์ชัน?

คำตอบ:


386

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

เรามาเริ่มด้วยวินาทีfnกันดีกว่า fnเป็นการปิดคล้ายกับlambdaในทับทิม เราสามารถสร้างมันได้ดังนี้:

x = 1
fun = fn y -> x + y end
fun.(2) #=> 3

ฟังก์ชั่นสามารถมีหลายส่วนได้ด้วย:

x = 1
fun = fn
  y when y < 0 -> x - y
  y -> x + y
end
fun.(2) #=> 3
fun.(-2) #=> 3

ตอนนี้ลองทำสิ่งที่แตกต่างกัน ลองกำหนดส่วนคำสั่งที่ต่างกันโดยคาดว่าจะมีอาร์กิวเมนต์ต่างกัน:

fn
  x, y -> x + y
  x -> x
end
** (SyntaxError) cannot mix clauses with different arities in function definition

ไม่นะ! เราได้รับข้อผิดพลาด! เราไม่สามารถผสมข้อที่คาดว่าจะมีข้อโต้แย้งที่แตกต่างกัน ฟังก์ชั่นจะมีค่าคงที่เสมอ

ตอนนี้เรามาพูดถึงฟังก์ชั่นที่ตั้งชื่อไว้:

def hello(x, y) do
  x + y
end

ตามที่คาดไว้พวกเขามีชื่อและพวกเขายังสามารถรับข้อโต้แย้งบางอย่าง อย่างไรก็ตามพวกเขาไม่ได้ปิด:

x = 1
def hello(y) do
  x + y
end

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

เราสามารถเรียกฟังก์ชัน hello ชื่อด้านบนเป็นฟังก์ชันที่ไม่ระบุชื่อได้ คุณพูดถึงตัวเอง:

other_function(&hello(&1))

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

ตั้งแต่ Elixir v0.10.1 เรามีไวยากรณ์ในการจับฟังก์ชั่นที่มีชื่อ:

&hello/1

ที่จะจับฟังก์ชั่นที่มีชื่อท้องถิ่นสวัสดีกับ arity 1 ตลอดภาษาและเอกสารของมันมันเป็นเรื่องธรรมดามากที่จะระบุฟังก์ชั่นในhello/1ไวยากรณ์นี้

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

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


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

17
มันไม่ได้เป็นข้อ จำกัด ของการนำไปใช้งานในแง่ที่ว่ามันสามารถทำงานเป็นf()(โดยไม่มีจุด)
José Valim

6
คุณสามารถจับคู่กับจำนวนของข้อโต้แย้งโดยใช้is_function/2ในยาม is_function(f, 2)ตรวจสอบว่ามันมี arity เท่ากับ 2 :)
José Valim

20
ฉันต้องการฟังก์ชั่นการเรียกใช้ที่ไม่มีจุดสำหรับทั้งฟังก์ชั่นที่มีชื่อและไม่ระบุชื่อ มันทำให้สับสนในบางครั้งและคุณลืมว่าฟังก์ชั่นบางอย่างไม่ระบุชื่อหรือตั้งชื่อ นอกจากนี้ยังมีเสียงดังมากขึ้นเมื่อมาถึงการแกง
CMCDragonkai

28
ใน Erlang, ฟังก์ชั่นการโทรไม่ระบุชื่อและฟังก์ชั่นปกติอยู่แล้วที่แตกต่างกัน syntactically: และSomeFun() some_fun()ใน Elixir ถ้าเราลบจุดพวกมันจะเหมือนกันsome_fun()และsome_fun()เนื่องจากตัวแปรใช้ตัวระบุเดียวกันกับชื่อฟังก์ชั่น ดังนั้นจุด
José Valim

17

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

ทุกสิ่งในน้ำอมฤตคือการแสดงออก ดังนั้น

MyModule.my_function(foo) 

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

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

หากคุณถามตัวเอง:

ฉันต้องการสภาพแวดล้อมการทำงานหรือค่าข้อมูลในจุดนี้หรือไม่?

และถ้าคุณต้องการใช้การประมวลผลให้ใช้ fn ความยุ่งยากส่วนใหญ่ก็จะชัดเจนขึ้น


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

ฉันคิดว่าคุณต้องการ: &MyModule.my_function/1นั่นคือวิธีที่คุณสามารถผ่านมันไปเป็นฟังก์ชั่น
jnmandal

14

ฉันไม่เคยเข้าใจว่าทำไมคำอธิบายของเรื่องนี้จึงซับซ้อน

มันเป็นเพียงความแตกต่างเล็ก ๆ น้อย ๆ เป็นพิเศษรวมกับความเป็นจริงของสไตล์ทับทิม

เปรียบเทียบ:

def fun1(x, y) do
  x + y
end

ถึง:

fun2 = fn
  x, y -> x + y
end

ขณะที่ทั้งคู่เป็นเพียงตัวระบุ ...

  • fun1defเป็นตัวบ่งชี้ที่อธิบายฟังก์ชั่นการตั้งชื่อที่กำหนดไว้กับ
  • fun2 คือตัวระบุที่อธิบายตัวแปร (ที่เกิดขึ้นเพื่อให้มีการอ้างอิงถึงฟังก์ชั่น)

ลองพิจารณาความหมายเมื่อคุณเห็นfun1หรือfun2แสดงออกอื่น เมื่อประเมินนิพจน์นั้นคุณเรียกใช้ฟังก์ชันที่อ้างอิงหรือคุณเพียงแค่อ้างอิงค่าหน่วยความจำนอก

ไม่มีวิธีที่ดีที่จะรู้เวลารวบรวม Ruby มีความหรูหราในการตรวจสอบตัวแปรเนมสเปซเพื่อตรวจสอบว่าการโยงตัวแปรมีเงาของฟังก์ชัน ณ เวลาใดเวลาหนึ่งหรือไม่ น้ำอมฤตที่ถูกรวบรวมไม่สามารถทำเช่นนี้ได้ นั่นคือสิ่งที่ dot-notation ทำมันบอก Elixir ว่ามันควรจะมีการอ้างอิงฟังก์ชั่นและมันควรจะเรียกว่า

และนี่เป็นเรื่องยากจริงๆ ลองนึกภาพว่ามันไม่มีเครื่องหมายจุด พิจารณารหัสนี้:

val = 5

if :rand.uniform < 0.5 do
  val = fn -> 5 end
end

IO.puts val     # Does this work?
IO.puts val.()  # Or maybe this?

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


12

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

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

my_function // argument
(function() {}) // argument

my_function() // function is called
(function() {})() // function is called

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

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

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

my_lambda.call
my_lambda.call()
my_lambda_with_arguments.call :h2g2, 42
my_lambda_with_arguments.call(:h2g2, 42)

ตอนนี้มีใครบางคนขึ้นมาด้วยทางลัดซึ่งโดยทั่วไปดูเหมือนว่าวิธีการที่ไม่มีชื่อ

my_lambda.()
my_lambda_with_arguments.(:h2g2, 42)

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

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

วงเล็บบังคับ VS สัญกรณ์ที่แตกต่างกันเล็กน้อย

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

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

และในน้ำอมฤตก็แค่จุดพิเศษนี้เท่านั้นในทับทิมคุณมีบล็อกอยู่ด้านบน บล็อกเป็นเรื่องที่น่าอัศจรรย์ใจและฉันรู้สึกประหลาดใจที่คุณสามารถทำอะไรกับบล็อกได้มากแค่ไหน แต่มันก็ใช้ได้เมื่อคุณต้องการฟังก์ชั่นนิรนามเพียงตัวเดียวซึ่งเป็นอาร์กิวเมนต์สุดท้าย จากนั้นเนื่องจากคุณควรจะสามารถจัดการกับสถานการณ์อื่น ๆ ต่อไปนี้เป็นวิธีการทั้งหมด / lambda / proc / block สับสน

อย่างไรก็ตาม ... มันอยู่นอกขอบเขต


9

มีโพสต์บล็อกที่ยอดเยี่ยมเกี่ยวกับพฤติกรรมนี้: ลิงค์

ฟังก์ชั่นสองประเภท

หากโมดูลมีสิ่งนี้:

fac(0) when N > 0 -> 1;
fac(N)            -> N* fac(N-1).

คุณไม่สามารถตัดและวางสิ่งนี้ลงในเปลือกเพื่อให้ได้ผลลัพธ์เดียวกัน

เป็นเพราะมีข้อผิดพลาดใน Erlang โมดูลใน Erlang มีลำดับของรูปแบบ Erlang เปลือกประเมินลำดับของ สำนวน ใน Erlang รูปแบบไม่ได้สำนวน

double(X) -> 2*X.            in an Erlang module is a FORM

Double = fun(X) -> 2*X end.  in the shell is an EXPRESSION

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

จุดในการโทร fn

iex> f = fn(x) -> 2 * x end
#Function<erl_eval.6.17052888>
iex> f.(10)
20

ในโรงเรียนฉันเรียนรู้ที่จะเรียกใช้ฟังก์ชั่นโดยการเขียน f (10) ไม่ใช่ f (10) - นี่คือ“ จริงๆ” ฟังก์ชั่นที่มีชื่อเช่น Shell.f (10) (มันเป็นฟังก์ชั่นที่กำหนดในเชลล์) ส่วนของเชลล์คือ โดยนัยดังนั้นจึงควรเรียกว่า f (10)

หากคุณปล่อยไว้อย่างนี้คาดว่าจะใช้เวลายี่สิบปีถัดไปในชีวิตของคุณอธิบายว่าทำไม


ฉันไม่แน่ใจว่ามีประโยชน์ในการตอบคำถาม OP โดยตรง แต่ลิงก์ที่ให้ไว้ (รวมถึงส่วนความคิดเห็น) เป็น IMO ที่อ่านได้อย่างยอดเยี่ยมสำหรับกลุ่มเป้าหมายของคำถามนั่นคือพวกเราใหม่กับ & การเรียนรู้ Elixir + Erlang .

ลิงค์นี้ตายแล้ว :(
AnilRedshift

2

Elixir มีวงเล็บปีกกาเสริมสำหรับฟังก์ชันรวมถึงฟังก์ชันที่มี 0 arity มาดูตัวอย่างว่าทำไมจึงทำให้การเรียกไวยากรณ์แยกต่างหากสำคัญ:

defmodule Insanity do
  def dive(), do: fn() -> 1 end
end

Insanity.dive
# #Function<0.16121902/0 in Insanity.dive/0>

Insanity.dive() 
# #Function<0.16121902/0 in Insanity.dive/0>

Insanity.dive.()
# 1

Insanity.dive().()
# 1

หากไม่สร้างความแตกต่างระหว่างฟังก์ชั่น 2 ประเภทเราไม่สามารถพูดได้ว่าInsanity.diveหมายถึงอะไร: รับฟังก์ชั่นเองเรียกมันหรือเรียกฟังก์ชั่นที่ไม่ระบุชื่อ


1

fn ->ไวยากรณ์สำหรับการใช้ฟังก์ชั่นที่ไม่ระบุชื่อ การทำ var. () เป็นการบอกยาอายุวัฒนะว่าฉันต้องการให้คุณใช้ var นั้นด้วย func ในนั้นและรันแทนการอ้างถึง var เป็นสิ่งที่เพิ่งถือฟังก์ชั่นนั้น

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

มันค่อนข้างแปลกที่จะคุ้นเคยกับการทำฟังก์ชั่นการกำหนดชวเลข (func (& 1) ฯลฯ ) แต่มีประโยชน์เมื่อคุณพยายามที่จะไพพ์หรือทำให้รหัสของคุณกระชับ


0

มีเพียงฟังก์ชันประเภทที่สองที่ดูเหมือนเป็นวัตถุชั้นหนึ่งและสามารถส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันอื่นได้ ฟังก์ชั่นที่กำหนดไว้ในโมดูลจะต้องห่อใน fn มีน้ำตาลซินแทคติคที่ดูเหมือนotherfunction(myfunction(&1, &2))จะทำให้ง่าย แต่ทำไมมันจำเป็นในตอนแรก? ทำไมเราทำotherfunction(myfunction))ไม่ได้?

คุณทำได้ otherfunction(&myfunction/2)

ตั้งแต่ยาอายุวัฒนะสามารถดำเนินการได้โดยไม่ต้องฟังก์ชั่นวงเล็บ (ชอบmyfunction) ใช้ก็จะพยายามที่จะดำเนินการotherfunction(myfunction))myfunction/0

ดังนั้นคุณต้องใช้ตัวดำเนินการจับภาพและระบุฟังก์ชั่นรวมถึง arity เนื่องจากคุณสามารถมีฟังก์ชั่นต่าง ๆ ที่มีชื่อเดียวกัน ดังนั้น&myfunction/2.

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