Fable: ์šฐํ™”์— ๋Œ€ํ•œ Python ์ง€์›

์— ๋งŒ๋“  2021๋…„ 01์›” 04์ผ  ยท  54์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: fable-compiler/Fable

์„ค๋ช…

์ด ๋ฌธ์ œ๋Š” Fable์— ๋Œ€ํ•œ Python ์ง€์›์— ๋Œ€ํ•œ ํ† ๋ก ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ Fable์—์„œ ์‚ฌ์šฉํ•˜๋Š” Babel AST๋Š” Python ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์„ ๋งŒํผ ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ด์ œ ํด๋ž˜์Šค๊ฐ€ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด POC๊ฐ€ ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๋งŽ์€ ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  1. Python์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ์ง€์› ์ถ”๊ฐ€
  2. Fable์„ JS์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  ์—ฌ๋Ÿฌ ๋Œ€์ƒ ์–ธ์–ด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

Expression ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” F#์—์„œ ์˜๊ฐ์„ ๋ฐ›์€ Python์˜ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. option , result , seq , map , list (FrozenList๋ผ๊ณ  ํ•จ), ์‚ฌ์„œํ•จ๊ณผ ๊ฐ™์€ ๋ฐ์ดํ„ฐ ์œ ํ˜•์˜ ์ž์ฒด ๊ตฌํ˜„์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์„œ, ... ๋”ฐ๋ผ์„œ Fable ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํ•ด๋‹นํ•˜๋Š” Python์œผ๋กœ ์ ํ•ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Python์—์„œ๋Š” Expression์„ ์‚ฌ์šฉํ•˜์—ฌ F#ish ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. Fable์—์„œ๋Š” Expression์„ ์‚ฌ์šฉํ•˜์—ฌ Python ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์‚ฌ๋ก€:

  • Python ์ปค๋„์ด ์žˆ๋Š” Jupyter ๋…ธํŠธ๋ถ์—์„œ ์‹คํ–‰๋˜๋Š” F#, ์˜ˆ๋ฅผ ๋“ค์–ด Hy ๋ฐ Calysto Hy๋กœ ์ˆ˜ํ–‰๋˜๋Š” ์ž‘์—…๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
  • ๋งˆ์ฐฐ ๊ฐ์†Œ๋ฅผ ์œ„ํ•ด Python์„ ์‚ฌ์šฉํ•œ F# ์Šคํฌ๋ฆฝํŒ…
  • micro:bit ๋ฐ Rasberry PI ์™€ ๊ฐ™์€ ์ž„๋ฒ ๋””๋“œ ํ™˜๊ฒฝ์„ ๋ณด๋‹ค ์‰ฝ๊ฒŒ โ€‹โ€‹์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  • F#๊ณผ Python ์ฝ”๋“œ ๊ฐ„์— ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ๊ณต์œ 

๋…ผ์˜ํ•˜๊ณ  ๊ฒฐ์ •ํ•  ์‚ฌํ•ญ:

  • F#์šฉ Python์ด .NET๋ณด๋‹ค Python์ ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๋Œ€์ฒดํ•˜๊ฑฐ๋‚˜ ๊ฒฝ์Ÿํ•ด์„œ๋Š” ์•ˆ ๋˜๋Š” Jupyter์— ๋Œ€ํ•œ .NET ์ง€์›์ด ์ด๋ฏธ ์žˆ์Šต๋‹ˆ๋‹ค. Fable for Python์€ .NET(๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ) ๋Œ€์‹  Python์„ ๋Œ€์ƒ์œผ๋กœ ํ•ด์•ผ ํ•˜๋ฉฐ F#์„ ์ฐพ๋Š” Python ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ ํ•ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Babel AST์™€ ํ˜ธํ™˜๋˜๋„๋ก ๋…ธ๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ์ž์ฒด Python AST๋กœ ๋ถ„๊ธฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์•„๋งˆ๋„ ํ”ผํ•  ์ˆ˜ ์—†๋Š” ์ผ์ด์ง€๋งŒ Babel์€ ์šฐ๋ฆฌ์—๊ฒŒ ์ข‹์€ ์ถœ๋ฐœ์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • ์šฐ๋ฆฌ๋Š” Fable์„ ์œ„ํ•ด ( Peeble ๊ณผ
  • Python ๊ธฐ๋ณธ ์œ ํ˜•๋„ F#๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด int ๋Š” ์ž„์˜์˜ ๊ธธ์ด๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. ํ˜ธํ™˜๋˜๋„๋ก .NET(๋จธ์‹ ) ์œ ํ˜•์„ ์—๋ฎฌ๋ ˆ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด Python int ์œ ํ˜•์„ F# int๋กœ ๋…ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

POC ์„ค์น˜

POC์˜ ์†Œ์Šค ์ฝ”๋“œ๋Š” ํ˜„์žฌ ์—ฌ๊ธฐ์— ์žˆ์Šต๋‹ˆ๋‹ค:

  1. https://www.python.org ์—์„œ ์ตœ์‹  Python 3.9๋ฅผ ์„ค์น˜ํ•˜๊ฑฐ๋‚˜ Mac์—์„œ brew install [email protected] ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ์€ ์‹œ์Šคํ…œ์—์„œ python , python3 ๋˜๋Š” ๋‘˜ ๋‹ค๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๋‘ ์ €์žฅ์†Œ๋ฅผ ๋ชจ๋‘ ๋ณต์ œํ•˜๊ณ  python ๋ถ„๊ธฐ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  3. Python์šฉ ์šฐํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌ์ถ•: dotnet fsi build.fsx library-py
  4. ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด: dotnet fsi build.fsx test-py
  5. Fable์—์„œ QuickTest.fs ๋ฅผ ์•„์ฃผ ๊ฐ„๋‹จํ•œ F# ์ฝ”๋“œ๋กœ ํŽธ์ง‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ตœ์ƒ์œ„ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ dotnet fsi build.fsx quicktest ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ Fable ๋ฐ Expression ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ํŽธ์ง‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ•„์š”ํ•  ๋•Œ ์˜ˆ์ œ ์ฝ”๋“œ๊ฐ€ ๋‹ค์‹œ ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค. Fable ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•œ ํ›„ ์žฌ์ปดํŒŒ์ผ์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ ค๋ฉด QuickTest.fs ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ €์žฅ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ ํŒŒ์ผ์€ quicktest.py ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ข‹์€ ๋ฐ๋ชจ๋Š” vscode์—์„œ F#, JS ๋ฐ Python์„ ๋™์‹œ์— ๋ณด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด F# ํŒŒ์ผ์„ ์ €์žฅํ•  ๋•Œ ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜๋˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Screenshot 2021-01-15 at 13 18 09

ํ„ฐ๋ฏธ๋„์—์„œ ์ƒ์„ฑ๋œ Python ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ python3 quicktest.py

์—ฐ๊ฒฐ

๋ช‡ ๊ฐ€์ง€ ๊ด€๋ จ ๋งํฌ:

ํ† ๋ก , ์˜๊ฒฌ, ์•„์ด๋””์–ด ๋ฐ ์ฝ”๋“œ๋กœ ์ž์œ ๋กญ๊ฒŒ ๊ธฐ์—ฌํ•˜์‹ญ์‹œ์˜ค ๐Ÿ˜

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋ฉ‹์ง„ ์ž‘ํ’ˆ์ž…๋‹ˆ๋‹ค @dbattli! ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ Fable์˜ ์›๋ž˜ ์•„์ด๋””์–ด๋Š” F#์„ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์‰ฝ๊ฒŒ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ข‹๋“  ๋‚˜์˜๋“  Fable์€ JS๋ฅผ ์ฃผ์š” ์ดˆ์ ์œผ๋กœ ๋ฐœ์ „์‹œ์ผœ ์™”๊ธฐ ๋•Œ๋ฌธ์— ์–ธ์–ด์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ฒŒ ํ•˜๋ ค๋ฉด ์•ฝ๊ฐ„์˜ ์ž‘์—…์ด ํ•„์š”ํ•˜์ง€๋งŒ ์ด์— ๋Œ€ํ•ด ๊ฐœ๋ฐฉ์ ์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ์˜๊ฒฌ:

  • ๊ฐ™๊ฑฐ๋‚˜ ๋‹ค๋ฅธ repo? ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ๊ณตํ†ต ์ฝ”๋“œ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ๋ถ„๊ธฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ(์ธ์šฉ ์ง€์›์œผ๋กœ ๋ถ„๊ธฐ๋ฅผ ๋™๊ธฐํ™”ํ•˜๊ธฐ๊ฐ€ ์ด๋ฏธ ์–ด๋ ต์Šต๋‹ˆ๋‹ค) ๋Œ€์ƒ ์–ธ์–ด์— ๋”ฐ๋ผ ๋ชจ๋“  ๊ณณ์—์„œ ์กฐ๊ฑด์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ์ฝ”๋“œ๋ฅผ ์ถฉ๋ถ„ํžˆ ๋ชจ๋“ˆํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ค‘๊ฐ„ ์†”๋ฃจ์…˜์€ Fable "Nucleus"(Core ๐Ÿ˜‰๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ)์— ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์ถ”์ถœํ•œ ๋‹ค์Œ ์–ธ์–ด ๊ตฌํ˜„์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ์ €์žฅ์†Œ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • Babel AST: ์ด๊ฒƒ์€ ์›๋ž˜ ์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋“œ ์ธ์‡„๋ฅผ ์œ„ํ•ด Babel์— ์˜์กดํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒ์ ์ธ ์„ธ๊ณ„์—์„œ๋Š” ์ด์ œ ํ”„๋ฆฐํ„ฐ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Fable-to-Babel ๋‹จ๊ณ„์—์„œ ๋งŽ์€ ์ผ์ด ์ผ์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋ ค์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ์ด์œ ๋กœ ์ด ๋‹จ๊ณ„์—์„œ ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•„๋งˆ๋„ Babel AST๋ฅผ ๋น„๊ธฐ๋Šฅ์  ์–ธ์–ด์— ๋Œ€ํ•ด ์ข€ ๋” ์ผ๋ฐ˜์ ์ธ ๊ฒƒ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์˜ˆ:

    • ์‹ ๊ธฐ๋ฐ˜ AST์—์„œ ์‹/๋ฌธ AST๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. JS์˜ ๊ฒฝ์šฐ ์—ฌ๊ธฐ์—๋Š” ๋„ˆ๋ฌด ๋งŽ์€ IIFE๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•  ๋•Œ ๋ณ€์ˆ˜ ์„ ์–ธ์„ ํ•จ์ˆ˜์˜ ๋งจ ์œ„๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
    • ํŒจํ„ด ์ผ์น˜(DecisionTree)๋ฅผ if/switch ๋ฌธ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ผฌ๋ฆฌ ํ˜ธ์ถœ ์ตœ์ ํ™”. ์ด๊ฒƒ์€ JS ๋ ˆ์ด๋ธ” ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ์—์„œ๋Š” ์ค‘์ฒฉ ๋ฃจํ”„์—์„œ ๊นจ์ง€์ง€ ์•Š๋„๋ก ๋‹ค๋ฅธ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ๊ณ ์œ  ์‹๋ณ„์ž๋กœ ๋ณ€ํ™˜(ํ•„์š”ํ•œ ๊ฒฝ์šฐ Fable AST์—์„œ ์ง์ ‘ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Œ).
  • F#์„ ๋” Pythonicํ•˜๊ฒŒ ๋งŒ๋“œ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? Fable์„ ์‚ฌ์šฉํ•˜๋ฉด ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด .NET ์˜๋ฏธ ์ฒด๊ณ„๊ฐ€ ๋•Œ๋•Œ๋กœ ํฌ์ƒ๋˜๋Š” ๊ท ํ˜•์„ ์ฐพ๊ธฐ ์œ„ํ•ด ํ•ญ์ƒ ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ๋Š” int์— ๋Œ€ํ•ด ํŠน์ • ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  JS ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(long์— ๋Œ€ํ•ด ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€๋งŒ). ์ด๊ฒƒ์€ Python int ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ˆ๋ฅผ ๋“ค์–ด ์ •์ˆ˜ ๋‚˜๋ˆ„๊ธฐ ๋˜๋Š” ๋ช…์‹œ์  ์ˆซ์ž ๋ณ€ํ™˜๊ณผ ๊ฐ™์€ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๊ฒฐ๊ณผ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํŠน์ • ์ง€์ ์—์„œ .NET ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ์กด์ค‘ํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ๊ธฐ์—ฌ๋ฅผ ํ–ˆ์Šต๋‹ˆ๋‹ค.
    ์–ด์จŒ๋“  "๋” ํŒŒ์ด์ฌ์ ์ธ"์ด๋ผ๊ณ  ๋งํ•˜๋ฉด ์ฝ”๋“œ ์Šคํƒ€์ผ ๋˜๋Š” ๊ธฐ๋ณธ API๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? Fable์€ ๋Œ€๋ถ€๋ถ„์˜ .NET BCL์„ ์ง€์›ํ•˜๋ ค๊ณ  ํ•˜์ง€ ์•Š์ง€๋งŒ ๊ฒฐ๊ตญ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ต์ˆ™ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ณตํ†ต ๊ธฐ๋Šฅ/์—ฐ์‚ฐ์ž๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์‹ ๊ทœ ์‚ฌ์šฉ์ž๋„ ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—). ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ๊ธฐ๋ณธ API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค( ๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ Fable.Extras ๋Š” ์ข‹์€ ์›€์ง์ž„์ž…๋‹ˆ๋‹ค). ์˜ˆ๋ฅผ ๋“ค์–ด JS.console.log ์ผ๋ฐ˜์ ์œผ๋กœ printfn ๋ณด๋‹ค ๊ฐœ์ฒด์˜ ํ˜•์‹์„ ์ง€์ •ํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ›„์ž๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  54 ๋Œ“๊ธ€

๋ฉ‹์ง„ ์ž‘ํ’ˆ์ž…๋‹ˆ๋‹ค @dbattli! ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ Fable์˜ ์›๋ž˜ ์•„์ด๋””์–ด๋Š” F#์„ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์‰ฝ๊ฒŒ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ข‹๋“  ๋‚˜์˜๋“  Fable์€ JS๋ฅผ ์ฃผ์š” ์ดˆ์ ์œผ๋กœ ๋ฐœ์ „์‹œ์ผœ ์™”๊ธฐ ๋•Œ๋ฌธ์— ์–ธ์–ด์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ฒŒ ํ•˜๋ ค๋ฉด ์•ฝ๊ฐ„์˜ ์ž‘์—…์ด ํ•„์š”ํ•˜์ง€๋งŒ ์ด์— ๋Œ€ํ•ด ๊ฐœ๋ฐฉ์ ์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ์˜๊ฒฌ:

  • ๊ฐ™๊ฑฐ๋‚˜ ๋‹ค๋ฅธ repo? ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ๊ณตํ†ต ์ฝ”๋“œ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ๋ถ„๊ธฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ(์ธ์šฉ ์ง€์›์œผ๋กœ ๋ถ„๊ธฐ๋ฅผ ๋™๊ธฐํ™”ํ•˜๊ธฐ๊ฐ€ ์ด๋ฏธ ์–ด๋ ต์Šต๋‹ˆ๋‹ค) ๋Œ€์ƒ ์–ธ์–ด์— ๋”ฐ๋ผ ๋ชจ๋“  ๊ณณ์—์„œ ์กฐ๊ฑด์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ์ฝ”๋“œ๋ฅผ ์ถฉ๋ถ„ํžˆ ๋ชจ๋“ˆํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ค‘๊ฐ„ ์†”๋ฃจ์…˜์€ Fable "Nucleus"(Core ๐Ÿ˜‰๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ)์— ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์ถ”์ถœํ•œ ๋‹ค์Œ ์–ธ์–ด ๊ตฌํ˜„์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ์ €์žฅ์†Œ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • Babel AST: ์ด๊ฒƒ์€ ์›๋ž˜ ์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋“œ ์ธ์‡„๋ฅผ ์œ„ํ•ด Babel์— ์˜์กดํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒ์ ์ธ ์„ธ๊ณ„์—์„œ๋Š” ์ด์ œ ํ”„๋ฆฐํ„ฐ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Fable-to-Babel ๋‹จ๊ณ„์—์„œ ๋งŽ์€ ์ผ์ด ์ผ์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋ ค์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ์ด์œ ๋กœ ์ด ๋‹จ๊ณ„์—์„œ ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•„๋งˆ๋„ Babel AST๋ฅผ ๋น„๊ธฐ๋Šฅ์  ์–ธ์–ด์— ๋Œ€ํ•ด ์ข€ ๋” ์ผ๋ฐ˜์ ์ธ ๊ฒƒ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์˜ˆ:

    • ์‹ ๊ธฐ๋ฐ˜ AST์—์„œ ์‹/๋ฌธ AST๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. JS์˜ ๊ฒฝ์šฐ ์—ฌ๊ธฐ์—๋Š” ๋„ˆ๋ฌด ๋งŽ์€ IIFE๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•  ๋•Œ ๋ณ€์ˆ˜ ์„ ์–ธ์„ ํ•จ์ˆ˜์˜ ๋งจ ์œ„๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
    • ํŒจํ„ด ์ผ์น˜(DecisionTree)๋ฅผ if/switch ๋ฌธ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ผฌ๋ฆฌ ํ˜ธ์ถœ ์ตœ์ ํ™”. ์ด๊ฒƒ์€ JS ๋ ˆ์ด๋ธ” ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ์—์„œ๋Š” ์ค‘์ฒฉ ๋ฃจํ”„์—์„œ ๊นจ์ง€์ง€ ์•Š๋„๋ก ๋‹ค๋ฅธ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ๊ณ ์œ  ์‹๋ณ„์ž๋กœ ๋ณ€ํ™˜(ํ•„์š”ํ•œ ๊ฒฝ์šฐ Fable AST์—์„œ ์ง์ ‘ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Œ).
  • F#์„ ๋” Pythonicํ•˜๊ฒŒ ๋งŒ๋“œ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? Fable์„ ์‚ฌ์šฉํ•˜๋ฉด ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด .NET ์˜๋ฏธ ์ฒด๊ณ„๊ฐ€ ๋•Œ๋•Œ๋กœ ํฌ์ƒ๋˜๋Š” ๊ท ํ˜•์„ ์ฐพ๊ธฐ ์œ„ํ•ด ํ•ญ์ƒ ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ๋Š” int์— ๋Œ€ํ•ด ํŠน์ • ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  JS ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(long์— ๋Œ€ํ•ด ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€๋งŒ). ์ด๊ฒƒ์€ Python int ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ˆ๋ฅผ ๋“ค์–ด ์ •์ˆ˜ ๋‚˜๋ˆ„๊ธฐ ๋˜๋Š” ๋ช…์‹œ์  ์ˆซ์ž ๋ณ€ํ™˜๊ณผ ๊ฐ™์€ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๊ฒฐ๊ณผ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํŠน์ • ์ง€์ ์—์„œ .NET ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ์กด์ค‘ํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ๊ธฐ์—ฌ๋ฅผ ํ–ˆ์Šต๋‹ˆ๋‹ค.
    ์–ด์จŒ๋“  "๋” ํŒŒ์ด์ฌ์ ์ธ"์ด๋ผ๊ณ  ๋งํ•˜๋ฉด ์ฝ”๋“œ ์Šคํƒ€์ผ ๋˜๋Š” ๊ธฐ๋ณธ API๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? Fable์€ ๋Œ€๋ถ€๋ถ„์˜ .NET BCL์„ ์ง€์›ํ•˜๋ ค๊ณ  ํ•˜์ง€ ์•Š์ง€๋งŒ ๊ฒฐ๊ตญ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ต์ˆ™ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ณตํ†ต ๊ธฐ๋Šฅ/์—ฐ์‚ฐ์ž๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์‹ ๊ทœ ์‚ฌ์šฉ์ž๋„ ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—). ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ๊ธฐ๋ณธ API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค( ๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ Fable.Extras ๋Š” ์ข‹์€ ์›€์ง์ž„์ž…๋‹ˆ๋‹ค). ์˜ˆ๋ฅผ ๋“ค์–ด JS.console.log ์ผ๋ฐ˜์ ์œผ๋กœ printfn ๋ณด๋‹ค ๊ฐœ์ฒด์˜ ํ˜•์‹์„ ์ง€์ •ํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ›„์ž๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด ์•„์ด๋””์–ด๋ฅผ ์ข‹์•„ํ•œ๋‹ค. ํŠนํžˆ F#์—์„œ Python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ๊ณ ๋Œ€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” ์ˆœ์ˆ˜ Python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” SciSharp๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Python๊ณผ ๊ฑฐ์˜ ๋™์ผํ•œ API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค(Python ๋˜๋Š” .NET ์ปจํ…์ŠคํŠธ์—์„œ ์‹คํ–‰๋˜๋Š” ๋™์ผํ•œ F# ์ฝ”๋“œ!)

์ด๋Ÿฌํ•œ F# ์ฝ”๋“œ๋Š” Fable์„ ์‚ฌ์šฉํ•˜์—ฌ Python์œผ๋กœ ์ปดํŒŒ์ผํ•œ ๋‹ค์Œ Notebooks ์ปค๋„(Jupyter ๋˜๋Š” .NET Interactive) ๋‚ด์—์„œ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ„์„ ์›Œํฌํ”Œ๋กœ๋ฅผ ์‹ค์ œ ๋„๋ฉ”์ธ ์ค‘์‹ฌ ๊ธฐ๋Šฅ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ด ๋ชจ๋“  ๊ฒƒ์„ "์ฃฝ์ด๋Š” ๊ธฐ๋Šฅ"์œผ๋กœ ๊ฐ„์ฃผํ•  ์ˆ˜ ์žˆ์Œ).

.NET Interactive๋Š” ํ™•์žฅ์„ฑ์ด ๋งค์šฐ ๋›ฐ์–ด๋‚˜ F# ์ปค๋„ ๋‚ด์—์„œ Fable์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค(์ž‘์—… ์ค‘์ธ PoC๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค).

๋˜ ๋‹ค๋ฅธ ์ ์€ MS๊ฐ€ ๊ณง ์ „์ฒด .NET์— ๋Œ€ํ•ด ์œ ์‚ฌํ•œ ์กฐ์šฉํ•œ ๊ฒƒ์„ ๊ณต๊ฐœํ•  ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ธกํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(์˜ˆ์ธก์€ .NET Interactive๊ฐ€ ๋‹ค๋ฃจ๋Š” ํ™œ๋™๊ณผ ๋ชฉํ‘œ์—๋งŒ ๊ธฐ๋ฐ˜ํ•˜๋ฏ€๋กœ ํ‹€๋ฆด ์ˆ˜ ์žˆ์Œ). ๊ทธ๋“ค์ด ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์šฐ๋ฆฌ๋Š” Fable์ด ๊ธฐ๋Šฅ์  ์„ธ๊ณ„์—์„œ ์™„์ „ํ•œ JS/F#/Python ๋ฌด๊ธฐ๊ณ ๋ฅผ ๊ฐ–๊ธฐ ์œ„ํ•ด ๋ณ„๋„๋กœ ๊ทธ๊ฒƒ์„ ๊ฐ–๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. MS ์ ‘๊ทผ ๋ฐฉ์‹์€ Blazor-flavour์™€ ๋” ๋น„์Šทํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค(๋‚ด ์ƒ๊ฐ์—).

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ @alfonsogarciacaro , @PawelStadnicki์— ๋Œ€ํ•œ ํ›Œ๋ฅญํ•œ ํ”ผ๋“œ๋ฐฑ์ž…๋‹ˆ๋‹ค. ๋‚ด ๋ง์€ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ .NET์„ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜๋Š” ๋Œ€์‹  Python ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฅผ ๋” ๋งŽ์ด ๋…ธ์ถœํ•˜์—ฌ "Python" ๋Š๋‚Œ์„ ๊ฐ–๊ฒŒ ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์˜€์Šต๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋ฉด .NET์„ ๋Œ€์‹  ์‚ฌ์šฉํ•ด์•ผ ํ•จ).

๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋‘ ์„ธ๊ณ„์—์„œ ๊ฐ€์žฅ ์ข‹์€ ๊ฒƒ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ  ๋ฌด์—‡์„ ๊ฐ€์ ธ์˜ฌ์ง€ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒฐ์ •ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: Python์—์„œ datetime ๋˜๋Š” .NET์—์„œ DateTime ). ๋”ฐ๋ผ์„œ ๊ฒฐ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ๊ฐ€์žฅ ์›ํ•˜๋Š” ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค(์ฃผ๋ฌธํ˜•). ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ Fable JS์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์›น ์•ฑ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๋ชจ๋“  .NET์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•˜์ง€๋Š” ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. JS ์ƒํƒœ๊ณ„์— ๋” ์ž˜ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฏธ๋ฆฌ ๊ฒฐ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์†Œ๋งค๋ฅผ ๊ฑท์–ด๋ถ™์ด๊ณ  ์‹œ์ž‘ํ•ด ๋ด…์‹œ๋‹ค ๐Ÿ˜„ Fable์˜ ์ผ๋ถ€๊ฐ€ ๋˜์–ด ์ด ๋ฌธ์ œ๋ฅผ ํ†ตํ•ด ๋ณ€ํ˜• ๋“ฑ์— ๋Œ€ํ•ด ์งˆ๋ฌธํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋ฐฐ์šธ ๊ฒƒ์ด ๋งŽ์Šต๋‹ˆ๋‹ค.

์ถ”์‹ : Expression btw์—๋Š” ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ผฌ๋ฆฌ ํ˜ธ์ถœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋„ ์žˆ์Šต๋‹ˆ๋‹ค(๋™๊ธฐํ™” ๋ฐ ๋น„๋™๊ธฐํ™” ๋ชจ๋‘). ๋‹ค์Œ์€ aioreactive์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ ์ž…๋‹ˆ๋‹ค.

#1601์ด ์ƒ๊ฐ๋‚˜๋„ค์š”.

Fable์„ ํƒ€์‚ฌ ๋ฐฑ์—”๋“œ "ํ”Œ๋Ÿฌ๊ทธ์ธ"(LLVM์„ ์ƒ๊ฐํ•˜์ง€๋งŒ F#์—๋งŒ ํ•ด๋‹น)์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์„ ๋งŒํผ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋ฌดํ•œํ•œ ๊ฐ€๋Šฅ์„ฑ.

Babel AST๋ฅผ ์ข€ ๋” ์ผ๋ฐ˜์ ์ด๊ณ  ํ˜•์‹ํ™”ํ•˜์—ฌ C์™€ ๊ฐ™์€ ์–ธ์–ด๋กœ ์‰ฝ๊ฒŒ ๋ณ€ํ™˜/์ธ์‡„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋…ธ๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Fable์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋™์•ˆ ๋ฐฐ์šด ๊ฒƒ์ด ์žˆ๋‹ค๋ฉด ๊ฐ„๋‹จํ•œ F#์—์„œ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ์˜ ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด (์–ด๋Š ์ •๋„) ์‰ฝ์ง€๋งŒ ์ข‹์€ ๊ฐœ๋ฐœ ๊ฒฝํ—˜๊ณผ ํ†ตํ•ฉ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ F#์˜ ์žฅ์ ์€ ์™ธ๊ตญ ์ƒํƒœ๊ณ„๋Š” ๋ชจ๊ตญ์–ด๋กœ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋ฌด๊ฒ์Šต๋‹ˆ๋‹ค.

@alfonsogarciacaro๊ฐ€ ๋งํ•œ ๊ฒƒ. ๊ทธ ๊ณผ์ œ์˜ ์ผ๋ถ€๋Š” Fable BCL ๊ตฌํ˜„์„ F#์œผ๋กœ ๋” ๋งŽ์ด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜์—ฌ ๋ชจ๋“  ์–ธ์–ด์— ๋Œ€ํ•ด ๋‹ค์‹œ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํฅ๋ฏธ๋กœ์šด. Fable BCL ๊ตฌํ˜„์˜ ์ƒ๋‹น ๋ถ€๋ถ„์ด (์•„๋งˆ๋„) Javascript๋กœ ์ž‘์„ฑ๋˜์—ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์ด๋ฏธ ๋” ๋งŽ์€ F#์ผ ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๊ทธ๋Ÿด๋งŒํ•œ ์ด์œ ๊ฐ€ ์žˆ๋‹ค๊ณ  ์˜์‹ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์›Œ์กŒ์„๊นŒ์š”?

@jwosty ๋Œ€๋‹ต์€ ์„ฑ๋Šฅ์ƒ์˜ ์ด์œ ๋กœ F# ์œ ํ˜•๊ณผ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›๋˜๋Š” ์œ ํ˜• ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๊ณ  ์ƒ์„ฑ๋œ ์ฝ”๋“œ๋ฅผ JavaScript ์—์ฝ”์‹œ์Šคํ…œ ๋‚ด์—์„œ ๋” ์ž˜ ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ .NET BCL ์—๋Š” FSharp.Core ์™ธ์—๋„ ๋งค์šฐ ํฐ API ํ‘œ๋ฉด์ด ์žˆ์œผ๋ฏ€๋กœ ๋” ํฐ ํŒ€ ์—†์ด๋Š” ์ด ๋…ธ๋ ฅ์„ ์œ ์ง€ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋†€๋ž๊ณ  ์นญ์ฐฌํ•  ๋งŒํ•˜๋‹ค).

๋‚ด๊ฐ€ ๋งํ•˜๋ ค๋Š” ๊ฒƒ์€ ๊ธฐ์—ฌ(๋ฐ ์•„์ด๋””์–ด)๊ฐ€ ๋งค์šฐ ํ™˜์˜๋ฐ›๊ณ  ๊ฐ์‚ฌํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

(๊ทธ๋ ‡๊ฒŒ ์งง์ง€ ์•Š์Œ) ๋Œ€๋‹ต์€ ์„ฑ๋Šฅ์ƒ์˜ ์ด์œ ๋กœ, F# ์œ ํ˜•๊ณผ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›๋˜๋Š” ์œ ํ˜• ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๊ณ  ์ƒ์„ฑ๋œ ์ฝ”๋“œ๋ฅผ JavaScript ์—์ฝ”์‹œ์Šคํ…œ ๋‚ด์—์„œ ๋” ์ž˜ ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งํ•˜๋ ค๋Š” ๊ฒƒ์€ ๊ธฐ์—ฌ(๋ฐ ์•„์ด๋””์–ด)๊ฐ€ ๋งค์šฐ ํ™˜์˜๋ฐ›๊ณ  ๊ฐ์‚ฌํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ™•์‹คํžˆ! ์ด๋งŒํผ ํฌ๊ณ  ์ค‘์š”ํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋…ธ๋ ฅ์„ ๊ธฐ์šธ์ด๊ณ  ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜๊ณ  ์—ฌ๋Ÿฌ๋ถ„์ด ์Ÿ์€ ํ”ผ์™€ ๋ˆˆ๋ฌผ์— ์ง„์‹ฌ์œผ๋กœ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. Fable์€ ์ตœ๊ทผ์— ์ €์—๊ฒŒ ๋งค์šฐ ์œ ์šฉํ–ˆ๊ณ  ๋Œ๋ ค๋“œ๋ฆฌ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์•ฝ๊ฐ„์˜ ๋„์›€์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ฐœ๋ฐœ์„ ์œ„ํ•ด QuickTest ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: dotnet fsi build.fsx quicktest ). ๊ฐœ๋ฐœํ•˜๋Š” ๋™์•ˆ Babel AST๋ฅผ ์–ด๋–ป๊ฒŒ ์ธ์‡„ํ•ฉ๋‹ˆ๊นŒ? ( ์—…๋ฐ์ดํŠธ : ASTViewer ๋ฅผ ์ฐพ์•˜

๋‚ด ํ˜„์žฌ ๋ฌธ์ œ๋Š” Python์ด ์—ฌ๋Ÿฌ ์ค„ ๋žŒ๋‹ค(ํ™”์‚ดํ‘œ ํ•จ์ˆ˜)๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋žŒ๋‹ค๊ฐ€ ๋ช…๋ช…๋œ ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ ๋ฐ ์ถ”์ถœ๋˜๊ณ  ๋Œ€์‹  ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์žˆ๋Š” ๋ชจ๋“  ํŒ์„ ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์˜ˆ:

let fn args cont  =
    cont args

let b = fn 10 (fun a ->
    a + 1
)

๋‹ค์Œ์œผ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

let fn args cont  =
    cont args

let cont a =
    a + 1
let b = fn 10 cont

ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ args๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ ๋” ๋†’์€ ์ˆ˜์ค€์—์„œ ๋Œ€์ฒดํ•ด์•ผ ํ•˜๊ฑฐ๋‚˜ if true then ... ๊ฐ™์€ ์ผ์ข…์˜ ๋ธ”๋ก ๋ช…๋ น๋ฌธ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜์˜ ํ˜ธ์ถœ ํ‘œํ˜„์‹์„ ์—ฌ๋Ÿฌ ๋ช…๋ น๋ฌธ์œผ๋กœ ๋Œ€์ฒดํ•  ๋•Œ ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•ด์•ผ ํ• ๊นŒ์š”?

@dbragtli ์†์„ฑ ์ค‘ ์ผ๋ถ€๋„ ์ธ์‡„ํ•˜๋Š” ์ด ํ”„๋ฆฐํ„ฐ ๋„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

Fable BCL ๊ตฌํ˜„์˜ ์ƒ๋‹น ๋ถ€๋ถ„์ด (์•„๋งˆ๋„) Javascript๋กœ ์ž‘์„ฑ๋˜์—ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์ด๋ฏธ ๋” ๋งŽ์€ F#์ผ ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ๋‹ค. ๊ทธ๋Ÿด๋งŒํ•œ ์ด์œ ๊ฐ€ ์žˆ๋‹ค๊ณ  ๋ฏฟ์–ด ์˜์‹ฌ์น˜ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์›Œ์กŒ์„๊นŒ์š”?

๋„ค, @ncave๊ฐ€ ๋งํ–ˆ๋“ฏ์ด ์ฃผ๋œ ์ด์œ ๋Š” ๋” ๋งŽ์€ ํ‘œ์ค€ JS๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Funscript์—์„œ๋Š” ๋ชจ๋“  FSharp.Core ๊ต์ฒด๊ฐ€ F#์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์ง€๋งŒ Fable์—์„œ๋Š” ๊ฐ€๋Šฅํ•˜๋ฉด JS ํ‘œ์ค€๊ณผ ํ†ตํ•ฉํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: .NET IEnumerable ๋Œ€์‹  JS ๋ฐ˜๋ณต๊ธฐ ์‚ฌ์šฉ). ์ฒ˜์Œ์—๋Š” JS/Typescript๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์› ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ์šฐํ™”-๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ JS ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ„๋„์˜ ํŒจํ‚ค์ง€๋กœ ํผ๋ธ”๋ฆฌ์‹ฑํ•  ์ƒ๊ฐ๋„ ์žˆ์—ˆ์ง€๋งŒ ๊ธˆ์„ธ ํ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค.

Fable 2์—์„œ ์šฐ๋ฆฌ๋Š” ์ผ๋ถ€ ๋ชจ๋“ˆ์„ F#์œผ๋กœ ์ด์‹ํ•˜๊ธฐ ์œ„ํ•œ ๋…ธ๋ ฅ์„ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ dogfooding์„ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  FSharp.Core์˜ ๊ฐœ์„  ์‚ฌํ•ญ์„ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ์œ ์ตํ–ˆ์Šต๋‹ˆ๋‹ค(์ตœ๊ทผ ๋งต ๋ฐ ์„ธํŠธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ). ๊ทธ๋Ÿฌ๋‚˜ ๋‹ญ๊ณผ ๊ณ„๋ž€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๊ธฐ ์ €๊ธฐ์— ์—ฌ์ „ํžˆ ๋ช‡ ๊ฐ€์ง€ ํ•ดํ‚น์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ต์ฒด ๋ชจ๋“ˆ์ธ ํฐ ๊ดด๋ฌผ์— ๋Œ€ํ•ด์„œ๋Š” ์ด์•ผ๊ธฐํ•˜์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. :)

๋˜ํ•œ @ncave๊ฐ€ ๋งํ–ˆ๋“ฏ์ด ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์—„์ฒญ๋‚œ ์ผ์ด๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€ ๊ด€๋ฆฌ ํ‘œ๋ฉด์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ํ•ญ์ƒ BCL์— ๋Œ€ํ•œ ์ง€์›์„ ๋Š˜๋ฆฌ๋Š” ๊ฒƒ์„ ๊บผ๋ คํ•˜์ง€๋งŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ํฐ ๊ณตํ—Œ์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๋งค์šฐ ์šด์ด ์ข‹์•˜์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ๋ถ€ํ„ฐ.

@dbrattli AST ์ธ์‡„์— ๋Œ€ํ•ด Fable repo์—์„œ ASTViewer ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€์ง€ ์˜ค๋ž˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋” ๋‚˜์€ ์˜ต์…˜์€ @ncave ๋˜๋Š” F# AST๋ฅผ ๊ฒ€์‚ฌํ•ด์•ผ ํ•  ๋•Œ ์ตœ๊ทผ์— ์‚ฌ์šฉํ•˜๋Š” Fantomas ์‹œ๊ฐํ™” ๋„์šฐ๋ฏธ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค( Show Typed AST ๋ฅผ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค). ๋ถˆํ–‰ํžˆ๋„ ์šฐ๋ฆฌ๋Š” ์•„์ง Fable ๋˜๋Š” Bable AST์— ๋Œ€ํ•œ ํŠน์ • ํ”„๋ฆฐํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Fable AST์˜ ๊ฒฝ์šฐ ๊ทธ๋ƒฅ ํ•ฉ์ง‘ํ•ฉ์ด๊ณ  ๊ฐ„๋‹จํ•œ printfn "%A" ์ž‘๋™ํ•˜์ง€๋งŒ ์œ„์น˜ ์ •๋ณด๊ฐ€ ์•ฝ๊ฐ„ ์‹œ๋„๋Ÿฝ์Šต๋‹ˆ๋‹ค.

๋žŒ๋‹ค ์ถ”์ถœ์— ๋Œ€ํ•ด. ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์•ฝ๊ฐ„์˜ ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์ ธ์˜ค๊ธฐ์™€ ์œ ์‚ฌํ•œ ์ž‘์—…, ์ฆ‰ AST๋ฅผ ํƒ์ƒ‰ํ•  ๋•Œ ์ˆ˜์ง‘ํ•˜๊ณ  ๊ณ ์œ ํ•œ ์‹๋ณ„์ž๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ์šฐ๋ฆฌ๋Š” ํŒŒ์ผ์˜ ๋งจ ์œ„์— ํ•จ์ˆ˜๋ฅผ ์„ ์–ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์š” ๋ฌธ์ œ๋Š” ์บก์ฒ˜๋œ ๊ฐ’์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. F# AST์— ์ด์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์žˆ๋Š”์ง€ ๊ธฐ์–ต๋‚˜์ง€ ์•Š์ง€๋งŒ, ์ •๋ณด๊ฐ€ ์žˆ๋”๋ผ๋„ ๋ถˆํ–‰ํžˆ๋„ AST์— ๋ณด๊ด€ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ธ์ˆ˜(๋˜๋Š” ๋žŒ๋‹ค ๋‚ด์˜ ๋ฐ”์ธ๋”ฉ)์— ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š” ๋žŒ๋‹ค ๋ณธ๋ฌธ์— ์‚ฌ์šฉ๋œ ๋ชจ๋“  idents๋ฅผ ์ฐพ์•„ ๋žŒ๋‹ค์˜ ์ถ”๊ฐ€ ์ธ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

@alfonsogarciacaro ์ข‹์€ ์ •๋ณด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ œ ์ฒซ PoC๋Š” Babel.fs / Fable2Babel.fs , BabelPrinter.fs ๋“ฑ์„ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋ณ„๋„์˜ Python AST ์ฆ‰ Python.fs ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค PythonPrinter.fs . ๊ทธ๋Ÿฐ ๋‹ค์Œ Fable AST์—์„œ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์‰ฌ์šธ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Babel AST์—์„œ Python AST๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด Babel2Python.fs ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค Fable2Python.fs ์–ด๋ ค์šด). ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ธฐ์กด ์ฝ”๋“œ ๊ธฐ๋ฐ˜์„ ๋„ˆ๋ฌด ๋งŽ์ด ๋งŒ์ง€์ง€ ์•Š๊ณ  ๋žŒ๋‹ค ์žฌ์ž‘์„ฑ์„ ์‹œ๋„ํ•  ๋‚˜๋งŒ์˜ ๋ณ€ํ™˜์„ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ์–ด๋ ค์›€์€ Babel AST๊ฐ€ DU๋กœ ๊ตฌ์„ฑ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒจํ„ด ์ผ์น˜๋กœ ํƒ์ƒ‰ํ•˜๊ธฐ๊ฐ€ ์กฐ๊ธˆ ๋” ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. #2158์ด ๋„์›€์ด ๋ ๊นŒ์š”?

@alfonsogarciacaro ๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” (ํฌ๋ง) ์‹ค์ œ๋กœ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์™€ ํ•จ์ˆ˜ ํ‘œํ˜„์‹์˜ ์žฌ์ž‘์„ฑ์„ ๊ณ ์น  ์ˆ˜ ์žˆ์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์•„์ด๋””์–ด๋Š” ๋ชจ๋“  ํ‘œํ˜„์‹( TransformAsExpr )์ด ๋ช…๋ น๋ฌธ ๋ชฉ๋ก(์—ฐ๊ฒฐ๋˜์–ด ๋งˆ์ง€๋ง‰ ๋ช…๋ น๋ฌธ ๋ชฉ๋ก(last-statement-level)๊นŒ์ง€ ์ „๋‹ฌ๋˜์–ด์•ผ ํ•จ)๋„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜๋œ ๋ช…๋ น๋ฌธ(func-def)์€ ์œ„๋กœ ๋“ค์–ด ์˜ฌ๋ ค ๋‹ค๋ฅธ ๋ช…๋ น๋ฌธ ์•ž์— ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ™”์‚ดํ‘œ ๋˜๋Š” ํ•จ์ˆ˜ ํ‘œํ˜„์‹์€ name-expression, [statement ] ๋ฅผ ๋ฆฌํ„ดํ•˜๋ฉฐ ์—ฌ๊ธฐ์„œ ํ™”์‚ดํ‘œ/ํ•จ์ˆ˜ ํ‘œํ˜„์‹์€ a๋กœ ๋‹ค์‹œ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋ช…๋ น๋ฌธ ๋ฐ ์ด๋ฆ„ ํ‘œํ˜„์‹๊ณผ ํ•จ๊ป˜ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

module QuickTest

let fn args cont  =
    cont args

let b = fn 10 (fun a ->
    printfn "test"
    a + 1
)

๋‹ค์Œ JS๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

import { printf, toConsole } from "./.fable/fable-library.3.1.1/String.js";

export function fn(args, cont) {
    return cont(args);
}

export const b = fn(10, (a) => {
    toConsole(printf("test"));
    return (a + 1) | 0;
});

๊ทธ๋Ÿฌ๋ฉด ๋‹ค์Œ Python์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

from expression.fable.string import (printf, toConsole)

def fn(args, cont):
    return cont(args)


def lifted_5094(a):
    toConsole(printf("test"))
    return (a + 1) | 0


b = fn(10, lifted_5094)

ํด๋กœ์ €๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ(๋ชจ๋“ ?) ํด๋กœ์ €๋„ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ:

module QuickTest

let add(a, b, cont) =
    cont(a + b)

let square(x, cont) =
    cont(x * x)

let sqrt(x, cont) =
    cont(sqrt(x))

let pythagoras(a, b, cont) =
    square(a, (fun aa ->
        printfn "1"
        square(b, (fun bb ->
            printfn "2"
            add(aa, bb, (fun aabb ->
                printfn "3"
                sqrt(aabb, (fun result ->
                    cont(result)
                ))
            ))
        ))
    ))

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค์‹œ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค.

from expression.fable.string import (printf, toConsole)

def add(a, b, cont):
    return cont(a + b)


def square(x, cont):
    return cont(x * x)


def sqrt(x, cont):
    return cont(math.sqrt(x))


def pythagoras(a, b, cont):
    def lifted_1569(aa):
        toConsole(printf("1"))
        def lifted_790(bb):
            toConsole(printf("2"))
            def lifted_6359(aabb):
                toConsole(printf("3"))
                return sqrt(aabb, lambda result: cont(result))

            return add(aa, bb, lifted_6359)

        return square(b, lifted_790)

    return square(a, lifted_1569)

์–ด์จŒ๋“  ์‹œ์ž‘์ด ์ข‹๋‹ค ๐Ÿ˜„

๋‚˜๋Š” PHP์— ๋Œ€ํ•ด ๋งค์šฐ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ ํ–ˆ์œผ๋ฉฐ(BGA ์—์„œ ์ค‘์ž„ ) ์—ฌ๊ธฐ์— ๋…ธ๋ ฅ์„ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

https://github.com/thinkbeforecoding/peeble

@ncave Jupyter ๋…ธํŠธ๋ถ๊ณผ ๊ฐ™์€ ๋Œ€ํ™”์‹ ์‚ฌ์šฉ์— Fable์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋ฌธ์ œ๋Š” Jupyter๊ฐ€ ์ฝ”๋“œ ์กฐ๊ฐ(์…€)์„ ์ œ๊ณตํ•˜๊ณ  ์ปค๋„์ด ์ด์ „ ๋ช…๋ น๋ฌธ์˜ ๊ธฐ์กด ๋กœ์ปฌ ์„ ์–ธ๊ณผ ํ•จ๊ป˜ ์ด ์กฐ๊ฐ์„ ์ปดํŒŒ์ผํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Fable์€ ์ด์— ์ตœ์ ์ด ์•„๋‹ˆ์ง€๋งŒ ์ด์ „ ๋ช…๋ น๋ฌธ/์„ ์–ธ(let, type, open)์˜ ์‚ฌ์ „์„ ์ˆœ์„œ๋Œ€๋กœ ์œ ์ง€ํ•˜๊ณ  ๋งˆ์ง€๋ง‰ ์ฝ”๋“œ ์กฐ๊ฐ๊ณผ ํ•จ๊ป˜ ์ˆœ์„œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์œ ํšจํ•œ F# ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“œ๋Š” PoC๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ ์กฐ๊ฐ์˜ ๋ชจ๋“  ์„ ์–ธ์€ ์‹คํ–‰ ์ „์— ์‚ฌ์ „์—์„œ ์ œ๊ฑฐ๋˜๊ณ  ์‹คํ–‰ ํ›„์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

์ถœ์ฒ˜: https://github.com/dbrattli/Fable.Jupyter/blob/main/fable/kernel.py#L85

๊ทธ๋Ÿฐ ๋‹ค์Œ Fable.fs๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ์ปดํŒŒ์ผํ•˜๋Š” Fable cli๊ฐ€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

dotnet watch -p src/Fable.Cli run -- watch --cwd /Users/dbrattli/Developer/GitHub/Fable.Jupyter --exclude Fable.Core --forcePkgs --python

@dbattli ์กฐ๊ฐ์ด ์ž‘์€ ๊ฒฝ์šฐ ํ•ฉ๋ฆฌ์ ์œผ๋กœ

์ฐธ๊ณ ๋กœ, ๋” ๋งŽ์€ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ CLI๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Fable์„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค( fable-standalone ๋ฐ ์‚ฌ์šฉ ์˜ˆ ์ฐธ์กฐ ).

1) ์ œ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฌธ์ œ๋Š” Fable AST์— ์Šค๋กœ์šฐ/๋ ˆ์ด์ฆˆ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ธฐ ์–ด๋ ค์šด Emit ํ‘œํ˜„์‹์œผ๋กœ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค. ๋˜๋Š” ์ ์–ด๋„ Babel์— ThrowStatement๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ๋ถˆํ•„์š”ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ๊ณ ์ณ์•ผ ํ•ฉ๋‹ˆ๊นŒ? @alfonsogarciacaro

let divide1 x y =
   try
      Some (x / y)
   with
      | :? System.DivideByZeroException -> printfn "Division by zero!"; None

let result1 = divide1 100 0

์ƒ์„ฑ:

export function divide1(x, y) {
    try {
        return ~(~(x / y));
    }
    catch (matchValue) {
        throw matchValue;
    }
}

export const result1 = divide1(100, 0);

์—ฌ๊ธฐ์„œ throw matchValue ๋Š” EmitExpression ์ž…๋‹ˆ๋‹ค.

2) ThisExpr ๋ฅผ Fable AST์— ์ถ”๊ฐ€ํ•ด์•ผ this ๊ฐ€ thisKeyword๋กœ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ™•์‹ค ํ•จ๊ป˜ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค Fable.IdentExpr ์„ค์ •๋˜์–ด this ๊ฐ€์ด - ํ‚ค์›Œ๋“œ์˜ ๊ฒฝ์šฐ ๋˜๋Š”ํ•˜์ง€ ์ด๋Ÿฌํ•œ ์š”๊ตฌ๊ฐ€ ๋ฒˆ์—ญ ๋  ๋•Œ๋ฌธ์— self ํŒŒ์ด์ฌํ•œ๋‹ค.
https://github.com/fable-compiler/Fable/blob/nagareyama/src/Fable.Transforms/Fable2Babel.fs#L792

์›ƒ๊ธฐ๋„ค์š”. throw๋Š” ์‹ค์ œ๋กœ Fable 2 AST์— ์žˆ์—ˆ์ง€๋งŒ Fable 3์—์„œ๋Š” ํ•œ ๊ณณ์—์„œ๋งŒ ์‚ฌ์šฉ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— AST๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์ œ๊ฑฐํ–ˆ์ง€๋งŒ ๋‹ค์‹œ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

"์ด๊ฒƒ"์— ๋Œ€ํ•ด์„œ๋Š” ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. F# AST์—์„œ๋Š” ์ƒ์„ฑ์ž๋‚˜ ๋ฉ”์„œ๋“œ์—์„œ ๋‹ค๋ฅด๊ฒŒ ํ‘œํ˜„๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์‹œ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์ฝ”๋“œ ์ „์ฒด์— ์ด์— ๋Œ€ํ•œ ์ฃผ์„์ด ํฉ์–ด์ ธ ์žˆ์Œ). Fable AST์—๋Š” ์‹๋ณ„์ž์— ๋Œ€ํ•œ IsThisArgument ์†์„ฑ์ด ์žˆ์ง€๋งŒ ์ด๊ฒƒ์ด ๋ถ„๋ฆฌ๋œ ๊ตฌ์„ฑ์›์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜์—๋งŒ ํ•ด๋‹นํ•˜๋Š”์ง€ ๋˜๋Š” "์‹ค์ œ this"์—๋„ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@alfonsogarciacaro "internal" ๋Œ€ "user" ์ปดํŒŒ์ผ๋œ ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•ฝ๊ฐ„์˜ ๋„์›€์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Exception have eg .message ํ•˜์ง€๋งŒ ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๋ฒˆ์—ญํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ์‚ฌ์šฉ์ž๊ฐ€ ์ปดํŒŒ์ผํ•œ ์ฝ”๋“œ์— .message ์—†๊ณ  ํ•ญ์ƒ ๋Œ€์‹  Test__Message_229D3F39(x, e) ๋กœ ๋๋‚˜์„œ ๊ฐ„์„ญํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด JsException ๊ฐœ์ฒด ๋‚ด์—์„œ catch'๋œ ์˜ˆ์™ธ๋ฅผ ๋ž˜ํ•‘ํ•˜๊ณ  ํ™•์‹คํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด .message ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? Fable์€ F#์—์„œ Babel๋กœ ์ด ์ž‘์—…์„ ์–ด๋–ป๊ฒŒ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๊นŒ? ์œ ํ˜•์„ ์ถ”์ ํ•ฉ๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด?

์˜ˆ๋ฅผ ๋“ค๋ฉด : ์–ด๋–ป๊ฒŒ ex.Message.StartsWith F์— #์ด ๋  ex.message.indexOf JS์—์„œ? ์ด๊ฒƒ์„ Python์—์„œ str(ex).index ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋˜๋Š” ๊ฐœ์ฒด๋ฅผ ๋ž˜ํ•‘).

์‹ค์ œ๋กœ F# ์˜ˆ์™ธ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: int * int์˜ ์˜ˆ์™ธ Foo). Fable 3 ๋ฆด๋ฆฌ์Šค ์ „์— ์ˆ˜์ •ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค ๐Ÿ˜… System.Exception์€ JS ์˜ค๋ฅ˜๋กœ ๋ณ€ํ™˜๋˜๋ฏ€๋กœ .message ํ•„๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ F# ์˜ˆ์™ธ๋Š” ์„ฑ๋Šฅ์ƒ์˜ ์ด์œ ๋กœ JS ์˜ค๋ฅ˜์—์„œ ํŒŒ์ƒ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ง€๊ธˆ์€ .Message์— ์•ก์„ธ์Šคํ•˜๋ ค๋Š” ์‹œ๋„๊ฐ€ ์‹คํŒจํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค). ์–ด๋”˜๊ฐ€์— ์ด๊ฒƒ์— ๋Œ€ํ•œ ํ† ๋ก ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ฒฝ์šฐ์™€ ์ผ๋ฐ˜์ ์ธ ์˜ˆ์™ธ์— ๋Œ€ํ•ด ์ง€๊ธˆ์€ Fable์ด .message ๋ฐ .stack ์†์„ฑ์— ์•ก์„ธ์Šคํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” Fable์—์„œ ์–ธ์–ด ์„ ํƒ์„ ์–ด๋–ป๊ฒŒ ์›ํ•ฉ๋‹ˆ๊นŒ? ์˜ค๋Š˜ ์šฐ๋ฆฌ๋Š” --typescript ์‚ฌ์šฉํ•˜์—ฌ TypeScript๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ --python ์‚ฌ์šฉํ•˜์—ฌ Python์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ .js ์ƒ์„ฑ์„ ์ค‘์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด Emit์ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ ์ƒ์„ฑ๋œ JS๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์•„๋งˆ๋„ ๊ทธ๋ž˜์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋•Œ๋•Œ๋กœ ์šฐ๋ฆฌ๋Š” JS๋ฅผ ๋ณด๊ณ  ์‹ถ์–ดํ•ฉ๋‹ˆ๋‹ค. --javascript ๋Œ€ํ•œ ์˜ต์…˜์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ JavaScript๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด --python ์—†์ด ์‹คํ–‰ํ•˜๋„๋ก ์š”๊ตฌํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? @alfonsogarciacaro

@dbrattli --typescript ๋Š” .ts ํŒŒ์ผ๋งŒ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ์›ํ•˜๋Š” ๊ฒฝ์šฐ --python ๋Š” .py ํŒŒ์ผ๋งŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๊ธฐ์ˆ ์ ์œผ๋กœ ๋ชจ๋‘ ์ƒํ˜ธ ๋ฐฐํƒ€์ ์ด๋ฏ€๋กœ ๋Œ€์‹  JavaScript/TypeScript/Python ๊ฐ’์„ ๊ฐ€์ง„ ์ƒˆ๋กœ์šด --language ์Šค์œ„์น˜๋ฅผ ๋„์ž…ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@ncave ์˜ˆ, JavaScript ๊ฐ€ ๊ธฐ๋ณธ๊ฐ’์ด ๋  ์ˆ˜ ์žˆ๋Š” [-lang|--language {"JavaScript"|"TypeScript"|"Python"}] ์™€ ๊ฐ™์€ ๊ฒƒ์ด ์ข‹์€ ์ƒ๊ฐ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ์— ๋Œ€ํ•œ ์–ธ์–ด ์†์„ฑ์„ ์ด๋ฏธ ์ถ”๊ฐ€ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์œผ๋ฏ€๋กœ ๋ช…๋ น์ค„ ์˜ต์…˜๋„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? https://github.com/fable-compiler/Fable/pull/2345/files#diff -9cb94477ca17c7556e6f79d71ed20b71740376f7f3b00ee0ac3fdd7e519ac577R12

์ผ๋ถ€ ์ƒํƒœ์ž…๋‹ˆ๋‹ค. Python ์ง€์›์ด ํ–ฅ์ƒ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋งŽ์€ ์–ธ์–ด ๊ธฐ๋Šฅ์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ๋‚จ์€ ํฐ ๊ณผ์ œ๋Š” ์šฐํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์‹ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ๋” ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Python์šฉ ์šฐํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ repo๋กœ ์ด๋™๋˜์—ˆ์œผ๋ฏ€๋กœ ๋งŽ์€ ์šฐํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ .fs ํŒŒ์ผ์„ Python์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋“ค ์ค‘ ๋‹ค์ˆ˜๋Š” ๊ฐ€๋กœ์ฑ„์„œ "์ˆ˜๋™์œผ๋กœ" ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” JS ๋ฐฉ์ถœ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. Python์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์„ค์ •(pytest ๊ธฐ๋ฐ˜)์€ ํ˜„์žฌ 43๊ฐœ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•œ ์ƒํƒœ์ด๋ฏ€๋กœ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•˜๊ณ  ์ถ”๊ฐ€ํ•˜๊ธฐ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์กŒ์Šต๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  ์ž‘๋™ ์ค‘์ธ ๊ธฐ๋Šฅ์„ ๋ณด์—ฌ์คŒ).

Python์šฉ ์šฐํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌ์ถ•: dotnet fsi build.fsx library-py
Python ํ…Œ์ŠคํŠธ ์‹คํ–‰: dotnet fsi build.fsx test-py

@dbattli
์ด์ƒ์ ์œผ๋กœ๋Š” fable-library ๋ฅผ F#์œผ๋กœ ๋” ๋งŽ์ด ๋ณ€ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. List ๋ฐ Seq ๋Š” ์ด๋ฏธ ์žˆ๊ณ  Array ๋Š” ์†Œ์ˆ˜์˜ ๊ธฐ๋ณธ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์•„๋งˆ๋„ ๋ถ„๋ฆฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ฝ๊ฐ„ ๋‹ค๋ฅธ ์ฃผ์ œ์— ๋Œ€ํ•ด Fable AST์—์„œ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  Babel AST์—์„œ ์ƒˆ๋กœ์šด ์–ธ์–ด ์ฝ”๋“œ์  ์„ ๊ตฌํ˜„ํ•˜๋Š” ์ฃผ์š” ์ด์ ์€ ๋ฌด์—‡์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?

@ncave Python๊ณผ JavaScript๋Š” ๋งค์šฐ ๊ฐ€๊น๊ธฐ ๋•Œ๋ฌธ์—(imo) Babel AST๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๊ธฐ๊ฐ€ ์ƒ๋Œ€์ ์œผ๋กœ ์‰ฝ์Šต๋‹ˆ๋‹ค. RxJS์—์„œ RxPY๋กœ ์ด์ „์— Python์œผ๋กœ ์•ฝ๊ฐ„์˜ JS๋ฅผ ์ด์‹ํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋˜ํ•œ "์—…์ŠคํŠธ๋ฆผ"์œผ๋กœ ๋งŒ๋“ค์–ด์ง€๋Š” ๋ชจ๋“  (๋ฒ„๊ทธ-)์ˆ˜์ •์˜ ์ด์ ์„ ์–ป์Šต๋‹ˆ๋‹ค. ์ฆ‰, Fable2Babel.fs ๋Œ€๋ถ€๋ถ„์„ ์žฌ์‚ฌ์šฉํ•˜๊ณ  Fable2Babel.fs ์™€ Babel2Python.fs ๋ฅผ ๊ฒฐํ•ฉ/์ถ•์†Œํ•˜๋Š” Fable2Python.fs ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Python์œผ๋กœ ์ง์ ‘ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์˜ค๋Š˜ ์ผ์ฐ ๊ทธ ์ƒ๊ฐ์„ ํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํฌํฌ์™€ ๋ฒ„๊ทธ ์ˆ˜์ •์ด ๋‘ ์œ„์น˜์— ๋ชจ๋‘ ์ ์šฉ๋˜์–ด์•ผ ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ Babel AST๋ฅผ ๋ณ€ํ˜•ํ•ด๋„ ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ฒฐ๊ตญ์—๋Š” Fable AST๋ฅผ ์ง์ ‘ ๋ณ€ํ˜•ํ•˜๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ‹์ง€๋„ค์š” @dbattli! ๋ชจ๋“  ์ž‘์—…์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์‚ฌ์‹ค, ๋‚ด๊ฐ€ ์—ผ๋‘์— ๋‘” ๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„์˜ Fable ์ฝ”๋“œ๋ฅผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋„ฃ๊ณ  fable(-js), fable-py(๋˜๋Š” ๋‹ค๋ฅธ ์ด๋ฆ„)์™€ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๊ตฌํ˜„์„ ๋…๋ฆฝ์ ์ธ dotnet ๋„๊ตฌ๋กœ ์ถœ์‹œํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฆด๋ฆฌ์Šค ์ฃผ๊ธฐ์—์„œ ๋” ๋งŽ์€ ์ž์œ ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์ง€๋งŒ ๋‘ ์–ธ์–ด๋กœ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ์ผ dotnet ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ฒ˜์Œ์—๋Š” ๋” ๊ฐ„๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

fable-library์— ๋Œ€ํ•ด ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•˜๋ฉด ํ˜„์žฌ .ts ํŒŒ์ผ์„ ํŒŒ์ด์ฌ์œผ๋กœ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹  F#์œผ๋กœ ํฌํŒ…ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Emit ์‚ฌ์šฉํ•˜์—ฌ ๋ถ€๋ถ„์„ ๋ถ„๋ฆฌํ•˜๊ณ  #if ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Python์— ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

#if FABLE_COMPILER_PYTHON
    [<Emit("print($0)")>]
    let log(x: obj) = ()

ใ€€// Other native methods ...
#else
    [<Emit("console.log($0)")>]
    let log(x: obj) = ()

    // ...
#endif

๋˜๋Š” ์ƒˆ๋กœ์šด "๋‹ค๊ตญ์–ด" Emit ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

type EmitLangAttribute(macros: string[]) =
    inherit Attribute()

[<EmitLang([|"js:console.log($0)"; "py:print($0)"|])>]
let log(x: obj) = ()

@alfonsogarciacaro ์™€ @ncave ์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ข‹์€ ์•„์ด๋””์–ด์ž…๋‹ˆ๋‹ค. ์–ด๋–ค ํšจ๊ณผ๊ฐ€ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ์‹œ๋„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. Fable-library๋ฅผ F#์œผ๋กœ ๋ฒˆ์—ญํ•˜๋Š” ๊ฒƒ์˜ ์ด์ ์„ ์•Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ Python ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ฑฐ๊ธฐ์—์„œ ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•˜๋ฉด ์—ฌ๊ธฐ์—์„œ ๋„์›€์„ ์ฃผ๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. #if ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งŽ์€ ๋„์›€์ด ๋  ๊ฒƒ์ด๋ฉฐ, ๋ฐฉ์ถœ์„ ์–ธ์–ด๋ณ„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŒŒ์ผ๋กœ ์ด๋™ํ•˜์—ฌ #if ํ”ผํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค(Python์— ๋Œ€ํ•œ ๋ณ„๋„์˜ .fsproj ํŒŒ์ผ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—).

@alfonsogarciacaro ๋Œ€์‹  ๋‘ ๊ฐœ์˜ ๋ฐฉ์ถœ ์†์„ฑ์ด ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? JS์˜ ๊ฒฝ์šฐ Emit, Python์˜ ๊ฒฝ์šฐ EmitPy. ํŒŒ์ด์ฌ ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๋Š” JS ๋“ฑ์— ๋Œ€ํ•ด ๋ฐฉ์ถœ์ด ๋ฐœ์ƒํ•˜๋ฉด ์™„ํ™”๋ฅผ ๋ณด๊ณ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด 2์„ผํŠธ์˜ ๊ฒฝ์šฐ, ๋‚˜๋Š” ๋‹จ์ˆœํžˆ ๋ฐฉ์ถœํ•˜๋Š” ๋‹จ์ผ ๋ฐฉ์ถœ ์†์„ฑ์„ ๊ฐ–๋Š” ํ˜„์žฌ์˜ ๋‚ฎ์€ ์ธ์ง€ ๋ถ€ํ•˜๋ฅผ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. @dbattli ๊ฐ€ ์ง€๊ธˆ ํ•˜๊ณ  ์žˆ๋Š” ์ผ์€ ์ดํ•ด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค(๊ฐ fable-library ์–ธ์–ด ๋ฒ„์ „๋งˆ๋‹ค ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ ํŒŒ์ผ). ๋‚˜์ค‘์— ํ˜ธ์ถœํ•  ์ž˜ ์ •์˜๋œ ์ธํ„ฐํŽ˜์ด์Šค(๋˜๋Š” ๋ชจ๋“ˆ)๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์ž์ฒด ํŒŒ์ผ์—์„œ ๋‹ค๋ฅธ ์–ธ์–ด ๋ฐฉ์ถœ์„ ์ผ๋ฐ˜ F# ๊ตฌํ˜„๊ณผ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ข‹์€ ์˜ˆ๋Š” Array.Helpers ๋ฅผ ๊ฐ ๋Œ€์ƒ ์–ธ์–ด์— ๋Œ€ํ•ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ณ€ํ™˜(๋˜๋Š” ๊ทธ๋ƒฅ ๋ชจ๋“ˆ๋กœ ๋‚จ๊ฒจ fable-library ๋ฅผ F#์œผ๋กœ ๋” ๋งŽ์ด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋ ค๋Š” ์ด๋Ÿฌํ•œ ๋…ธ๋ ฅ( --language ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜๋„ ํฌํ•จ)์€ ์ด PR๊ณผ ๋ณ„๋„์˜ PR์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋” ๋น ๋ฅด๊ณ  ์‰ฝ๊ฒŒ ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. .

์ข‹์€ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค @ncave :+1: ์‚ฌ์‹ค ์šฐ๋ฆฌ๋Š” ๋ฉ€ํ‹ฐํ”Œ๋žซํผ Fable ํ”„๋กœ์ ํŠธ(.net ๋ฐ js)์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•  ๋•Œ ์ด๋ฏธ ์ด๊ฒƒ์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ์„ ๋‹จ์ˆœํ™”ํ•˜๊ธฐ ์œ„ํ•ด Fable.Library์— ์ƒˆ Native.fs ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜์œ„ ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

namespace Fable.Library.Native            # or just Native

module Array = ..
module Map = ..

Emit ๋˜๋Š” Fable.Core.JS ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์„ ๊ทธ๊ณณ์œผ๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋น„๋™๊ธฐ ์ž‘์—…์—์„œ Async.ts ๋ฐ AsyncBuilder.ts ๋ฅผ F#์œผ๋กœ ์ด์‹ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ Async.fs ๋ฐ AsyncBuilder.fs ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด์ œ ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋œ ํ…Œ์ŠคํŠธ ํŒŒ์ผ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

async { return () }
|> Async.StartImmediate

Python(JS ์ฝ”๋“œ๋Š” ๋งค์šฐ ์œ ์‚ฌํ•ด์•ผ ํ•จ) ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

startImmediate(singleton.Delay(lambda _=None: singleton.Return()))

๊ทธ๋Ÿฌ๋‚˜ AsyncBuilder์—๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์—†์ง€๋งŒ AsyncBuilder__Delay_458C1ECD ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ AttributeError: 'AsyncBuilder' ๊ฐ์ฒด์— 'Delay' ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค.

class AsyncBuilder:
    def __init__(self):
        namedtuple("object", [])()

def AsyncBuilder__ctor():
    return AsyncBuilder()

def AsyncBuilder__Delay_458C1ECD(x, generator):
    def lifted_17(ctx_1):
        def lifted_16(ctx):
            generator(None, ctx)

        protectedCont(lifted_16, ctx_1)

    return lifted_17
...

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํžŒํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? @ncave @alfonsogarciacaro. ๋‚˜๋Š” F์˜ # ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ์™€ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑ ํ• , ๋˜๋Š” ๋‚ด ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์ฝ”๋“œ๊ฐ€ ์ƒ์„ฑ๋˜์–ด ๊ทธ ์šฉ๋„ ์ •์  AsyncBuilder__Delay_458C1ECD ๋Œ€์‹  .Delay() ?

@dbrattli ์ผ๋ฐ˜์ ์œผ๋กœ ๋ง๊ฐ€์ง€์ง€ ์•Š๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ด€๋ จ ๋ฉ”๋ชจ์—์„œ ๋น„๋™๊ธฐ ์ง€์›์€ ๋„ค์ดํ‹ฐ๋ธŒ Python asyncio ์˜ ๋ฒˆ์—ญ์— ๋” ์ ํ•ฉํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๊นŒ?

@ncave ์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ž‘๋™ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค ๐Ÿ˜„ ํ†ต์ฐฐ๋ ฅ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋”๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค ๋’ค์— ๋†“๊ณ  ๋„์›€์ด ๋˜๋Š”์ง€ ํ™•์ธํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค(F# ๋นŒ๋”๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์•„๋‹ˆ๋”๋ผ๋„ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•ด์•ผ ํ•จ). async ๊ด€ํ•ด์„œ๋Š” ๊ธฐ๋ณธ Python asyncio( ์—ฌ๊ธฐ ์ฐธ์กฐ )๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ณ„ํš์ด์—ˆ์ง€๋งŒ python cannot reuse already awaited coroutine ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ํ•จ์ˆ˜ ๋’ค์—์„œ ์ง€์—ฐ์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ์ €๋Š” Python ๋„ค์ดํ‹ฐ๋ธŒ awaitables์— task ๋˜๋Š” asyncio ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. AsyncBuilder.ts ์˜ ๋‹จ์ˆœํ™”๋Š” F#์œผ๋กœ ์ด์‹ํ•˜๋ ค๊ณ  ํ•˜๋Š” ์ €๋ฅผ ๋งค๋ฃŒ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

๋งน๊ธ€๋ง์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ @ncave๊ฐ€ ๋งํ•œ ๋Œ€๋กœ ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • NoOverloadSuffix ์†์„ฑ: Fable์ด ์˜ค๋ฒ„๋กœ๋“œ ์ ‘๋ฏธ์‚ฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ์˜ค๋ฒ„๋กœ๋“œ๋Š” ์ด ๊ฒฝ์šฐ์— ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

https://github.com/fable-compiler/Fable/blob/caa715f1156be29c8dd9b866a03031a1852b3186/src/fable-library/Map.fs#L524 -L527

๊ทธ๋Ÿฐ ๋‹ค์Œ Naming.buildNameWithoutSanitation ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/fable-compiler/Fable/blob/caa715f1156be29c8dd9b866a03031a1852b3186/src/Fable.Transforms/Replacements.fs#L1956 -L1963

  • ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ ํ›„ @ncave ๋Š” Fable์ด ์˜ˆ์ƒํ•œ ๋Œ€๋กœ(๋ช‡ ๊ฐ€์ง€ ์ œํ•œ ์‚ฌํ•ญ์ด ์žˆ๋Š”์ง€ ๊ธฐ์–ต๋‚˜์ง€ ์•Š์Œ) ๋งน๊ธ€๋ง๋œ ์ด๋ฆ„์„ ๋นŒ๋“œํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ F# ์ฝ”๋“œ๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด src/fable-library/System.Text.fs :

https://github.com/fable-compiler/Fable/blob/caa715f1156be29c8dd9b866a03031a1852b3186/src/Fable.Transforms/Replacements.fs#L1314 -L1326

์ด ๊ฒฝ์šฐ replacedModules ์‚ฌ์ „์— ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

https://github.com/fable-compiler/Fable/blob/caa715f1156be29c8dd9b866a03031a1852b3186/src/Fable.Transforms/Replacements.fs#L3075


๋”ฐ๋ผ์„œ ๋ถˆํ–‰ํžˆ๋„ Replacements ์—์„œ F#์œผ๋กœ ์ž‘์„ฑ๋œ ์šฐํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฝ”๋“œ์— ์—ฐ๊ฒฐํ•˜๋Š” ์ผ๊ด€๋œ ์ ‘๊ทผ ๋ฐฉ์‹์ด ์•„์ง ์—†์Šต๋‹ˆ๋‹ค. ์–ด์ฉŒ๋ฉด ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ ํ•˜๋‚˜์— ๋™์˜ํ•˜๊ธฐ ์œ„ํ•ด์ด ๊ธฐํšŒ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋งค์šฐ ํฅ๋ฏธ๋กœ์šด ํ†ต์ฐฐ๋ ฅ @ncave ๋ฐ @alfonsogarciacaro์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ๋‚˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. Python์—์„œ unit ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋‚ด ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

type IAsyncBuilder =
    abstract member Bind<'T, 'U> : IAsync<'T> * ('T -> IAsync<'U>) -> IAsync<'U>
    abstract member Combine<'T> : IAsync<unit> * IAsync<'T> -> IAsync<'T>
    abstract member Delay<'T> : (unit -> IAsync<'T>) -> IAsync<'T>
    abstract member Return<'T> : value: 'T -> IAsync<'T>
   ...

๋ฌธ์ œ๋Š” Return ๊ฐ€ ๋‹ค์Œ์„ ์ƒ์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

class AsyncBuilder:
    def Return(self, value):
        return protectedReturn(value)
    ....

์ด๊ฒƒ์€ ์ข‹์•„ ๋ณด์ด๊ณ  ์•„๋งˆ๋„ JS์— ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํŒŒ์ด์ฌ์—์„œ๋Š” ํ•จ์ˆ˜๊ฐ€ ์ธ์ˆ˜๋ฅผ ์ทจํ•˜๋Š” ๊ฒฝ์šฐ ์ธ์ˆ˜๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ 'T ๊ฐ€ unit ๋•Œ 'T x.Return() ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์ฒซ ๋ฒˆ์งธ ๋ฐ˜์‘์€ ๊ณผ๋ถ€ํ•˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์—ˆ์Šต๋‹ˆ๋‹ค.

abstract member Return : unit -> IAsync<unit>

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๋‚˜๋ฆ„์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ํ˜„์žฌ ์†”๋ฃจ์…˜(์ถ”ํ•œ ๋ชจ์–‘):

abstract member Return<'T> : [<ParamArray>] value: 'T [] -> IAsync<'T>

...

member this.Return<'T>([<ParamArray>] values: 'T []) : IAsync<'T> =
    if Array.isEmpty values then
        protectedReturn (unbox null)
    else
        protectedReturn values.[0]

๊ทธ๋Ÿฌ๋‚˜ ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ๋ชจ๋“  ์ผ๋ฐ˜ ๋‹จ์ผ ์ธ์ˆ˜ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๋ชจ๋“  ๋‹จ์ผ ์ธ์ˆ˜ ํ•จ์ˆ˜๊ฐ€ null(Python์˜ ๊ฒฝ์šฐ ์—†์Œ)์„ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„๋“ค์ด๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ:

class AsyncBuilder:
    def Return(self, value=None):
        return protectedReturn(value)
    ....

์ด ๋ฌธ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

IIRC, unit -> X ์„œ๋ช…์ด ์žˆ๋Š” ๋ฉ”์„œ๋“œ์˜ ๊ฒฝ์šฐ ํ˜ธ์ถœ์—๋Š” ์ธ์ˆ˜๊ฐ€ ์—†์ง€๋งŒ(F# AST์—์„œ์™€ ๊ฐ™์ด) ๋žŒ๋‹ค ๋˜๋Š” ์ด ๊ฒฝ์šฐ unit ํ˜ธ์ถœ/์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ฑ„์›Œ์ง„ ์ผ๋ฐ˜ ์ธ์ˆ˜์—๋Š” unit Fable AST์˜ transformCallArgs ๋„์šฐ๋ฏธ์—์„œ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๋Œ€์ƒ ์–ธ์–ด๊ฐ€ ํŒŒ์ด์ฌ์ผ ๋•Œ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๋‹จ์œ„ ์ธ์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ๋‘˜ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/fable-compiler/Fable/blob/caa715f1156be29c8dd9b866a03031a1852b3186/src/Fable.Transforms/Fable2Babel.fs#L1083 -L1086

์•ˆ๋…•ํ•˜์„ธ์š” @ncave , @alfonsogarciacaro , ์ €๋Š” Python์—์„œ [<Inject>] ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์ผ๋ถ€ ์ž…๋ ฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Php @thinkbeforecoding์—์„œ ์–ด๋–ป๊ฒŒ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด ( Array.fs ) ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ:

let map (f: 'T -> 'U) (source: 'T[]) ([<Inject>] cons: Cons<'U>): 'U[] =
    let len = source.Length
    let target = allocateArrayFromCons cons len
    for i = 0 to (len - 1) do
        target.[i] <- f source.[i]
    target

๋‚ด ์ฝ”๋“œ๋Š” cons ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์œผ๋ฉฐ Python์— ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

map(fn ar)

JS์˜ ๊ฒฝ์šฐ ์„ ํƒ ์‚ฌํ•ญ์ž…๋‹ˆ๊นŒ? ์ฝ”๋“œ์—์„œ ์†์„ฑ์„ ๊ฐ์ง€ํ•˜๊ณ  ์„ ํƒ์ ์œผ๋กœ ๋งŒ๋“ค๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ

def map(f, source, cons=None):
    ...

PHP๋Š” ๋˜ํ•œ ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•ด ๋ช…์‹œ์ ์ž…๋‹ˆ๋‹ค. ์ธ์ˆ˜ ๋ชจ๋ธ์— IsOptional ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

Fable์—์„œ Inject ์†์„ฑ์€ ๋‘ ๊ฐ€์ง€ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ์ฃผ๋กœ ์‹คํ—˜์ ์ด๋ฉฐ(์–ด๋–ป๊ฒŒ๋“  ์œ ํ˜• ํด๋ž˜์Šค๋ฅผ ์—๋ฎฌ๋ ˆ์ดํŠธํ•˜๊ณ  ์ผ๋ฐ˜ ์œ ํ˜• ์ •๋ณด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜๋ฅผ ์ธ๋ผ์ธํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด) ๋„ˆ๋ฌด ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์šฉ๋„๋Š” ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ํ•ด๊ฒฐ๋œ ์ธ์ˆ˜์— ์˜ํ•ด ์ „๋‹ฌ๋œ ์ถ”๊ฐ€ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ fable-library ๋ฉ”์„œ๋“œ์˜ ๋‚ด๋ถ€์ž…๋‹ˆ๋‹ค.

  • ๋ฐฐ์—ด์„ ๋นŒ๋“œํ•˜๋Š” ํ•จ์ˆ˜๋Š” ๊ทธ๊ฒƒ์ด JS ๋™์  ๋ฐฐ์—ด์ธ์ง€ ๋˜๋Š” ์œ ํ˜•์ด ์ง€์ •๋œ ๋ฐฐ์—ด์ธ์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์œ ํ˜•์„ ๋น„๊ตํ•ด์•ผ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ธฐ ์œ„ํ•ด ๋น„๊ต์ž๋ฅผ ์ˆ˜์‹ ํ•ด์•ผ ํ•˜๋Š” ์ƒ์„ฑ์ž ๋ฐ ๊ธฐํƒ€ ๋„์šฐ๋ฏธ๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค(์ผ๋ถ€ ํ‰๊ท  ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜์™€ ์œ ์‚ฌ).

๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜๋Š” ์ง์ ‘ ํ˜ธ์ถœ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ Fable์€ Inject ์†์„ฑ์„ "๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค". ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์–ด๋–ค ํ•จ์ˆ˜์— ์‚ฝ์ž…์ด ํ•„์š”ํ•œ์ง€ ์•Œ๋ ค์ฃผ๋Š” ReplacementInject.fs ํŒŒ์ผ ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ ๋ฐฉ๋ฒ• ๋ณด๊ธฐ: https://github.com/fable-compiler/Fable/blob/522f6aad211102271538798aeb90f4aed1f77dd6/src/Fable.Transforms/Replacements.fs#L988-L1019

์ด ํŒŒ์ผ์€ Fable.Library์˜ ์–ด๋–ค ํ•จ์ˆ˜๊ฐ€ Inject ์žฅ์‹๋œ ๋งˆ์ง€๋ง‰ ์ธ์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ๊ฐ์ง€ํ•˜๋Š” ์ด ์Šคํฌ๋ฆฝํŠธ๋กœ ์ฒ˜์Œ์— ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ด๋Š ์‹œ์ ์—์„œ ์šฐ๋ฆฌ๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ ์ค‘๋‹จํ•˜๊ณ  IIRC๊ฐ€ ReplacementInjects์— ๋Œ€ํ•œ ๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ๋ฅผ ์ค‘๋‹จํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ์ˆ˜๋™์œผ๋กœ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์„ ์•Œ๋ฉด IsOptional ์ •๋ณด๋ฅผ ์ œ๊ฑฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ... ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@alfonsogarciacaro ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ์— ๋Œ€ํ•ด injectArg ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

type Id = Id of string

let inline replaceById< ^t when ^t : (member Id : Id)> (newItem : ^t) (ar: ^t[]) =
    Array.map (fun (x: ^t) -> if (^t : (member Id : Id) newItem) = (^t : (member Id : Id) x) then newItem else x) ar

let ar = [| {|Id=Id"foo"; Name="Sarah"|}; {|Id=Id"bar"; Name="James"|} |]
replaceById {|Id=Id"ja"; Name="Voll"|} ar |> Seq.head |> fun x -> equal "Sarah" x.Name
replaceById {|Id=Id"foo"; Name="Anna"|} ar |> Seq.head |> fun x -> equal "Anna" x.Name

์—ฌ๊ธฐ์„œ Array.map ๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ฃผ์ž…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ์ฃผ์ž…๋œ ์ธ์ˆ˜ ์—†์ด JS๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

return map((x) => (equals(newItem.Id, x.Id) ? newItem : x), ar);

๋ฒ„๊ทธ์ธ๊ฐ€์š”? ์ด ์ฝ”๋“œ๋Š” JS(์šด์ด ์ข‹์€ ๊ฑธ๊นŒ์š”?)์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€๋งŒ Python์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์•„, ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค! ์™„์ „ํžˆ ์žŠ์–ด๋ฒ„๋ ธ์ง€๋งŒ "ํ‘œ์ค€" JS ๋ฐฐ์—ด์— ๋Œ€ํ•ด ๋ฐฐ์—ด ์ƒ์„ฑ์ž๊ฐ€ ์ฃผ์ž…๋˜์ง€ ์•Š์€ "์ตœ์ ํ™”"๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/fable-compiler/Fable/blob/4ecab5549ab6fcaf317ab9484143420671ded43b/src/Fable.Transforms/ ๊ต์ฒด.fs#L1005 -L1009

๊ทธ๋Ÿฐ ๋‹ค์Œ ์•„๋ฌด ๊ฒƒ๋„ ์ „๋‹ฌ๋˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ „์—ญ Array ์ž…๋‹ˆ๋‹ค. https://github.com/fable-compiler/Fable/blob/4ecab5549ab6fcaf317ab9484143420671ded43b/src/fable-library/Array.fs#L25 -L28

๋‚ด๊ฐ€ ์™œ ์ด๋ ‡๊ฒŒ ํ–ˆ๋Š”์ง€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด ๋ฒˆ๋“ค๋กœ ๋ช‡ ๋ฐ”์ดํŠธ๋ฅผ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋„์›€์ด ๋œ๋‹ค๋ฉด next ๋ถ„๊ธฐ์— ๋Œ€ํ•œ ์ด ์ตœ์ ํ™”๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•Œ์•˜์–ด ๊ณ ๋งˆ์›Œ. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ๋Œ ํ•„์š”๋Š” ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Python์ด ์งˆ์‹ํ•˜์ง€ ์•Š๋„๋ก ์„ธ ๋ฒˆ์งธ ์ธ์ˆ˜์— ๋Œ€ํ•ด ๋นˆ(null) ๊ฐ’์„ ์ƒ์„ฑํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰:

            | Types.arrayCons ->
                match genArg with
                | Number(numberKind,_) when com.Options.TypedArrays ->
                    args @ [getTypedArrayName com numberKind |> makeIdentExpr]
                | _ -> args @ [ Expr.Value(ValueKind.Null genArg, None) ]

JS์˜ ๊ฒฝ์šฐ ๋‹ค์Œ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

map((x_3) => (equals(newItem_1.Id, x_3.Id) ? newItem_1 : x_3), ar, null))).Name);

๊ทธ๋ฆฌ๊ณ  ํŒŒ์ด์ฌ์˜ ๊ฒฝ์šฐ:

def lifted_53(x_2):
    return newItem_1 if (equals(newItem_1["Id"], x_2["Id"])) else (x_2)

return map(lifted_53, ar, None)

๊ทธ๋Ÿฐ ๊ฒƒ์ด ์ˆ˜์šฉ ๊ฐ€๋Šฅํ•œ ์ˆ˜์ • ์‚ฌํ•ญ์ด ๋ ๊นŒ์š”?

์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  None ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ์‹œ์ ์—์„œ ์šฐ๋ฆฌ๋Š” Fable2Babel์˜ ๋งˆ์ง€๋ง‰ ์œ„์น˜์—์„œ None args๋ฅผ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ FSharp2Fable์—์„œ ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์— ์ถ”๊ฐ€ ๊ฒ€์‚ฌ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: https://github.com/fable-compiler/ ์šฐํ™”/blob/c54668b42b46c0538374b6bb2e283af41a6e5762/src/Fable.Transforms/Fable2Babel.fs#L1082 -L1095

BTW, ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค ์ด PR์„ ์ž์„ธํžˆ ํ™•์ธํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜… ํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„๋ฐ˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด PHP์—์„œ ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๊ณง POC๋กœ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Fable๋กœ ์—ฌ๋Ÿฌ ์–ธ์–ด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ๊ฒƒ์„ ๋” ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์•ฝ๊ฐ„์˜ ๋ฆฌํŒฉํ† ๋ง์„ ์ˆ˜ํ–‰ํ•  ๊ณ„ํš(์‹œ๊ฐ„ ํ—ˆ์šฉ) ๋•Œ๋ฌธ์ด๋ฉฐ, Python์ด ์ด๋ฏธ next ๋ถ„๊ธฐ์— ์žˆ๋‹ค๋ฉด ๋” ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๋„ˆ๋ฌด ๋งŽ์€ ๋ถ„๊ธฐ ๋ถ„๊ธฐ(main, next, python)๋ฅผ ๋™๊ธฐํ™” ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

์ข‹์•„ @alfonsogarciacaro , null ๋Œ€์‹  None์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ณง ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ๊ธฐ์กด Python ํ…Œ์ŠคํŠธ ์ค‘ ์ผ๋ถ€๋ฅผ ๊นจ๋œจ๋ฆฌ๊ณ  ์žˆ์ง€๋งŒ ์ด์ œ ๋ช‡ ๊ฐ€์ง€๋งŒ ๋‚จ์•˜๊ณ  ์ผ์ฃผ์ผ ์ •๋„ ์ด๋‚ด์— ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํ•„์š”ํ•œ ๋ฐฉ์ถœ๋กœ Fable.Core.PY.fs ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Babel2Python -> Fable2Python์˜ ์žฌ์ž‘์„ฑ์€ ์˜ˆ์ƒ๋ณด๋‹ค ์–ด๋ ค์› ์ง€๋งŒ ๋งˆ์นจ๋‚ด ๋‹ค์‹œ ์ •์ƒ ๊ถค๋„์— ์˜ค๋ฅด๊ธฐ ์œ„ํ•ด ๊ฐ€๊นŒ์›Œ์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. PR์„ ์กฐ๊ธˆ ์ •๋ฆฌํ•˜๊ณ  ๋ณ‘ํ•ฉํ•  ์ค€๋น„๋ฅผ ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@alfonsogarciacaro ํ•˜๋‚˜๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๋ฐ”๋ฒจ๋กœํ–ˆ๋‹ค ๋˜‘๊ฐ™์€ ๋ฌธ์ œ์— ๊ด€๋ จ์ด ๐Ÿ˜ฑ ๋‚ด๊ฐ€ ์•Œ๊ณ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š” Fable.Get ์˜จ ์‚ฌ์šฉ๋˜๋Š” AnonymousRecord ๊ทธ๋“ค์ด ํŒŒ์ด์ฌ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์œ ํ˜•, ๋‚ด๊ฐ€ ์‚ฌ์šฉ ์ฒจ์ž ํ•„์š” ์ฆ‰ [] ์•ก์„ธ์Šค๊ฐ€ ์•„๋‹ˆ๋ผ .dotted ์ž…๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์™ผ์ชฝ์ด ๋ฌด์—‡์ด๋“  ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ, ๊ฐ์ฒด, ํ•จ์ˆ˜ ํ˜ธ์ถœ ... ๊ทธ๋ž˜์„œ ์•Œ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ต๋ช… ๊ธฐ๋ก์„ ์œ„ํ•ด ๋˜ ๋‹ค๋ฅธ GetKind ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์ด๊ฒƒ์„ ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

FSharp2Fable์—์„œ ์ด๊ฒƒ์„ ๋ด…๋‹ˆ๋‹ค. FieldGet์ด AnonRecord์— ์˜ํ•ด ์ƒ์„ฑ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ๋‚˜์ค‘์— ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

    // Getters and Setters
    | FSharpExprPatterns.AnonRecordGet(callee, calleeType, fieldIndex) ->
        let r = makeRangeFrom fsExpr
        let! callee = transformExpr com ctx callee
        let fieldName = calleeType.AnonRecordTypeDetails.SortedFieldNames.[fieldIndex]
        let typ = makeType ctx.GenericArgs fsExpr.Type
        return Fable.Get(callee, Fable.FieldGet(fieldName, false), typ, r)

Discord @dbrattli ์—์„œ ์ด์•ผ๊ธฐํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์ต๋ช… ๋ ˆ์ฝ”๋“œ์ธ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜์‹ ์ž ์œ ํ˜•์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ณด๋‹ค ์ฒด๊ณ„์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ FieldGet ์— ๋” ๋งŽ์€ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ์‹œ์ ์—์„œ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ตœ์†Œํ™”ํ•˜๊ณ  ๋‹ค๋ฅธ ๋ถ€์šธ ํ•„๋“œ์™€ ํ˜ผ๋™์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋ณ„๋„์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์„ ์–ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(F#์€ ๋” ์—„๊ฒฉํ•œ ์œ ๋‹ˆ์˜จ ์ผ€์ด์Šค ํ•„๋“œ ์ด๋ฆ„ btw):

type FieldGetInfo =
    { Name: string
      IsMutable: bool
      IsAnonymousRecord: bool }

type GetKind =
    | FieldGet of info: FieldGetInfo
    | ...

@alfonsogarciacaro ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํšจ๊ณผ๊ฐ€ ์žˆ์—ˆ๋‹ค! ๐ŸŽ‰

๋‹ค์Œ ๋ฌธ์ œ:

testCase "Map.IsEmpty works" <| fun () ->
    let xs = Map.empty<int, int>
    xs.IsEmpty |> equal true
    let ys = Map [1,1; 2,2]
    ys.IsEmpty |> equal false

JS์˜ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค.

Testing_testCase("Map.isEmpty works", () => {
    Testing_equal(true, isEmpty_1(ofSeq([], {
        Compare: (x_1, y_1) => compare(x_1, y_1),
    })));
    Testing_equal(false, isEmpty_1(ofSeq([[1, 1]], {
        Compare: (x_2, y_2) => comparePrimitives(x_2, y_2),
    })));
})

ofSeq ๋Š” ๋‘ ๊ฐœ์˜ ์ธ์ˆ˜๋กœ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ofSeq ๋Š” ๋‹จ์ผ ์ธ์ˆ˜๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

let ofSeq elements =
    Map<_, _>.Create elements
export function ofSeq(elements) {
    return FSharpMap_Create(elements);
}

ofSeq ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ Compare ๊ฐ€ ์žˆ๋Š” ๊ฐœ์ฒด ํ‘œํ˜„์‹์ด ์ถ”๊ฐ€๋œ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

ํ , ์ด๊ฒƒ์— ๋Œ€ํ•ด ์กฐ์‚ฌํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ฒ„๊ทธ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ofSeq ๋Š” ๋น„๊ต์ž๋ฅผ ํ—ˆ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค( MapTree.ofSeq ๋ฐ Set.ofSeq ์™€ ๊ฐ™์€ ์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ์€ ์ˆ˜ํ–‰). ์„ค์ •์ด ์•ฝ๊ฐ„ ๋ณต์žกํ•˜๋ฏ€๋กœ ์–ด๋–ค ์‹œ์ ์—์„œ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์•˜์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€์ฒด์—์„œ ์ธ์ˆ˜ ์ฃผ์ž…์ด ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ReplacementsInject.fs๋ผ๋Š” ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์–ด๋”˜๊ฐ€์— ์žˆ์ง€๋งŒ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€์ง€ ์˜ค๋ž˜๋˜์–ด ์ตœ์‹  FCS ๋ฒ„์ „์—์„œ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค ์ง€์  ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

์ž„์‹œ ์ˆ˜์ •์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒ€ํ†  ์ค€๋น„ ๐ŸŽ‰ https://github.com/fable-compiler/Fable/pull/2345

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰