Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

最強JVM系関数型論理プログラミング言語、その名は Flix

最強JVM系関数型論理プログラミング言語、その名は Flix

Flixの簡単な紹介です(@第五回関数型プログラミング(仮)の会)

Kenichi SUZUKI

January 26, 2024
Tweet

More Decks by Kenichi SUZUKI

Other Decks in Programming

Transcript

  1. 4 Flix • 中心的な開発者はオーフス大学のMagnus Madsen先生 https://cs.au.dk/~magnusm/ 開発にはOSSコミュニティや研究者らが関わっている • Aarhus University(デンマーク)

    • the University of Waterloo(カナダ) • the University of Tübingen(ドイツ) • the University of Copenhagen(デンマーク)
  2. Hello WorldからみるFlix 8 def main(): Unit \ IO = println("Hello

    World!") 戻りの型 エフェクト def main(): String \ {} = "Hello World!" def main(): String = "Hello World!" エフェクトがないので Emptyになる エフェクトがない場合 は省略できる
  3. もちろんある、代数的データ型 9 enum Shape { case Circle(Int32), case Square(Int32), case

    Rectangle(Int32, Int32) } def area(s: Shape): Int32 = match s { case Shape.Circle(r) => 3 * (r * r) case Shape.Square(w) => w * w case Shape.Rectangle(h, w) => h * w } def main(): Unit \ IO = println(area(Shape.Rectangle(2, 4)))
  4. レコード 10 let p1 = { x = 1, y

    = 2 }; let p2 = { x = 3 | p1 }; p1.x + p2.x def f(r: {x = Int32, y = Int32}): Int32 = r.x + r.y def g(r: {x = Int32, y = Int32 | s}): Int32 = r.x + r.y g({x=1,y=2,z=3})
  5. レコード 11 def withAccountId(r: {| a}, aid: AccountId): {id =

    AccountId | a} = {+accountId=aid | r} def withoutName(r: {name = String | a}): {| a} = {-name | r}
  6. Region-based Local Mutation 局所的に破壊的変更ができる!パフォーマンスのいいプログラムが安全に書ける! 13 def toString(someList: List[a]): String with

    ToString[a] = region r { let sb = StringBuilder.new(r); foreach (x <- someList) { StringBuilder.appendString!("${x} :: ", sb) }; StringBuilder.appendString!("Nil", sb); StringBuilder.toString(sb) }
  7. 多相エフェクト mapのなかで副作用を起こしてしまう問題もこれで安心 14 def map(f: a -> b \ eff,

    xs: List[a]): List[b] \ eff = match l { case Nil => Nil case x :: xs => f(x) :: map(f, xs) }
  8. 型クラスの自動導出も便利 15 enum Month with Eq, Order, ToString { case

    January case February case March case April case May case June case July case August case September case October case November case December }
  9. 高階カインド 16 trait ForEach[t: Type -> Type] { pub def

    forEach(f: a -> Unit \ ef, x: t[a]): Unit \ ef } instance ForEach[List] { pub def forEach(f: a -> Unit \ ef, l: List[a]): Unit \ ef = match l { case Nil => () case x :: xs => f(x); ForEach.forEach(f, xs) } }
  10. forM, forA 17 def validateUsername(name: String): Validation[Err, UserName] = ...

    def validateJobType(jobType: String): Validation[Err, JobType] = ... def createAccount(n: UserName, j: JobType): Validation[Err, Account] = forA ( name <- validateUsername(n); jobType <- validateJobType(j) ) yield Account(name, jobType)
  11. 第一級 Datalog constraint 18 def main(): Unit \ IO =

    let facts = #{ Interpreter("x86"). Compiler("Scala", "x86", "MiniScala"). Compiler("MiniScala", "C++", "C++"). Compiler("C++", "x86", "x86"). }; let rules = #{ Compiler(src1, dst1, dst2) :- Compiler(src1, dst1, lang1), Compiler(lang1, dst2, lang2), Interpreter(lang2). Compiler(src, dst, lang) :- Compiler(src, intermediate, lang), Compiler(intermediate, dst, lang), Interpreter(lang). }; query facts, rules select (src, dst) from Compiler(src, _, dst) |> println
  12. 第一級 Datalog constraint 19 def main(): Unit \ IO =

    let facts = #{ Interpreter("x86"). Compiler("Scala", "x86", "MiniScala"). Compiler("MiniScala", "C++", "C++"). Compiler("C++", "x86", "x86"). }; let rules = #{ Compiler(src1, dst1, dst2) :- Compiler(src1, dst1, lang1), Compiler(lang1, dst2, lang2), Interpreter(lang2). Compiler(src, dst, lang) :- Compiler(src, intermediate, lang), Compiler(intermediate, dst, lang), Interpreter(lang). }; query facts, rules select (src, dst) from Compiler(src, _, dst) |> println Vector#{ (C++, x86), (MiniScala, C++), (MiniScala, x86), (Scala, C++), (Scala, MiniScala), (Scala, x86) }
  13. Flixの思想(一部) 21 • No NULL • No reflection • すべては式

    • ヒューマンリーダブルなエラー • 暗黙の強制(coercion)をしない • 純粋コードと不純(impure)コードを分離 • コンパイル結果にWarningはない、エラーのみ • 未使用の変数なし • 不要な宣言は不要 • グローバル状態なし • 構文の一貫性
  14. bug? 23 match userAccount { case RegularAccount(v) => doSomething(v) case

    SpecialAccount(v,tag) => bug!("The value of inputValue cannot be empty. tag: " + a) }
  15. ローカルでflix 25 ~/tmp/flix via ☕ v17.0.9 took 7s ❯ java

    -jar ./flix.jar init Creating '/tmp/flix/src'. Creating '/tmp/flix/test'. Creating '/tmp/flix/flix.toml'. Creating '/tmp/flix/.gitignore'. Creating '/tmp/flix/LICENSE.md'. Creating '/tmp/flix/README.md'. Creating '/tmp/flix/src/Main.flix'. Creating '/tmp/flix/test/TestMain.flix'. 用意するもの • java 21 • flix.jar ◦ https://github.com/flix/flix/releases ❯ java -jar ./flix.jar run Found `flix.toml'. Checking dependencies... Resolving Flix dependencies... Downloading Flix dependencies... Resolving Maven dependencies... Running Maven dependency resolver. Downloading external jar dependencies... Dependency resolution completed. Hello World!