DEV Community

loading...

ทำความเข้าใจ quoted expression ที่มี dot (.) ของ Elixir

Weerasak Chongnguluam
Software Developer/Love to code/Teaching to code
Updated on ・1 min read

สรุปเงื่อนไขของการ quote expression ที่มี dot (.) ของ Elixir

เมื่อวานเจอเคสที่ว่าถ้าเรามี Map แบบนี้

a = %{Body: "Hello"}
Enter fullscreen mode Exit fullscreen mode

ที่ key เป็น atom แต่ว่าขึ้นต้นด้วยตัวใหญ่ แล้วถ้าเราอยากใช้ syntax ที่ใช้ dot ในการ access ค่าใน key นี้

ปกติเราก็เขียนแบบนี้

a.Body
Enter fullscreen mode Exit fullscreen mode

แต่ว่าพอเขียนแบบนี้แล้วดันได้ error

** (CompileError) iex:10: invalid alias: "a.Body".
If you wanted to define an alias, an alias must expand
to an atom at compile time but it did not,
you may use Module.concat/2 to build it at runtime.
If instead you wanted to invoke a function or access a field,
wrap the function or field name in double quotes
Enter fullscreen mode Exit fullscreen mode

เลยสงสัยว่าทำไมมันมอง a.Body เป็น alisas แล้วไปพยายามไป expand a.Body ให้ได้ atom ค่านึงออกมา

เราสามารถทำความเข้าใจว่า Elixir มันแปลงโค้ดเราไปเป็น AST (Abstract Syntax Tree) อะไรได้โดยใช้ special form macro quote เช่นเคสนี้เราลองใช้ quote กับ a.Body ได้แบบนี้

a = %{Body: "Hello"}

quote do
  a.Body
end
Enter fullscreen mode Exit fullscreen mode

AST ที่ได้ออกมาเป็นแบบนี้

{:__aliases__, [], [{:a, [], Elixir}, :Body]}
Enter fullscreen mode Exit fullscreen mode

ในขณะที่ถ้า key ขึ้นต้นด้วยตัวเล็กจะได้ AST อีกแบบ

a = %{body: "Hello"}

quote do
  a.body
end
Enter fullscreen mode Exit fullscreen mode
{{:., [], [{:a, [], Elixir}, :body]}, [no_parens: true], []}
Enter fullscreen mode Exit fullscreen mode

เพราะ quote แล้วออกมาได้ต่างกันนั่นคือเหตุผลว่าทำไม a.Body ถึงถูกเอาไปจัดการ alias expand

ซึ่งกฎตรงนี้มีคำอธิบายใน document ของ quote ที่นี่ https://hexdocs.pm/elixir/1.11.2/Kernel.SpecialForms.html#./2-quoted-expression เอาไว้ว่า ถ้าใช้ . จะทำให้ quote ได้ 2 แบบโดยเงื่อนไขอยู่ที่ ค่าทางขวาของ . ถ้าค่าทางขวาขึ้นต้นด้วยตัวใหญ่ จะมองเป็น alias ถ้าเป็นตัวเล็ก จะได้ AST ที่เป็น qualified calls ปกติ

ทีนี้ถ้าเรายังอยากใช้ . เพื่อเป็น qualified calls สำหรับ access ค่าใน map ก็ยังใช้ได้ ถ้ากลับไปอ่าน error จะมีคำแนะนำอยู่คือใช้ double quote ครอบเอาไว้แบบนี้

a = %{Body: "Hello"}

a."Body"
Enter fullscreen mode Exit fullscreen mode

ซึ่งถ้า quote ดูก็จะได้แบบนี้

a = %{Body: "Hello"}

quote do
  a."Body"
end
Enter fullscreen mode Exit fullscreen mode
{{:., [], [{:a, [], Elixir}, :Body]}, [no_parens: true], []}
Enter fullscreen mode Exit fullscreen mode

Buy Me A Coffee

Discussion (1)

Collapse
veer66 profile image
Vee Satayamas

AST หน้าตาซับซ้อนมาก 😅