Upgrade to Pro — share decks privately, control downloads, hide ads and more …

皆さんはHaskellをご存知です_しかし皆さんはHaskellが読めません_.pdf

 皆さんはHaskellをご存知です_しかし皆さんはHaskellが読めません_.pdf

Avatar for noharu36

noharu36

May 16, 2026

More Decks by noharu36

Other Decks in Programming

Transcript

  1. 自己紹介 { name: 能島明希 handle: harukun origin: 広島->岡山->大阪->東京->会津 tech: {

    front-end: React+TS backend: Rust, Go, TS(勉強中) etc: Rust, Haskell Rust: Rust } favorites: Tobacco, BoyScout, Rust, Neovim, NixOS Twitter(x): https://twitter.com/pieceofharuki Blog: https://zenn.dev/haru_blog  update: 最近先輩の家に居候している(1K3人暮らし) }
  2. main = do [n, w] <- map readi . B.words

    <$> B.getLine :: IO [Int] xss <- map (map readi . B.words) <$> replicateM n B.getLine :: IO [[Int]] let f [x,y] = (fromIntegral x % fromIntegral y, y) :: (Rational, Int) yss = map f xss yss' = sortBy (comparing Down) yss ans = fromRational $ knapzak w 0 yss' :: Double printf "%.9f\n" $ ans knapzak :: Int -> Rational -> [(Rational, Int)] -> Rational knapzak w r [] = r knapzak w r (x:ps) | w == 0 = r | otherwise = knapzak w2 (r+r2) ps where (r2, w2) = g w x しかし皆さんは大学院の授業、 宣言的プログラミングを履修していないので Haskellで書かれたコードを読むことができません 🥺
  3. トランスパイラとは? あるプログラミング言語で書かれたコードを、別のプログラミング言語に変換するソフトウェア qsort [] = [] qsort (x:xs) = qsort

    smaller ++ [x] ++ qsort larger where smaller = [a | a <- xs, a <= x] larger = [b | b <- xs, b > x] fn qsort<T: Ord>(mut v: Vec<T>) -> Vec<T> { if let Some(p) = v.pop() { let (l, r): (Vec<_>, Vec<_>) = v.into_iter().partition(|x| x < &p); let mut res = qsort(l); res.push(p); res.extend(qsort(r)); return res; } v } Haskell Rust
  4. 字句解析 文字列をトークンに変換 トークン: 意味のあるかたまり 入力: "qsort [] = []" ↓

    字句解析 出力: Ident("qsort") ← 名前(識別子) Punctuation('[') ← 記号 Punctuation(']') ← 記号 Operator("=") ← 演算子 Punctuation('[') ← 記号 Punctuation(']') ← 記号 pub enum Token<'a> { Ident(&'a str), // 変数名: qsort, xs Literal(Literal<'a>), // 値: 42, "hello" Keyword(&'a str), // 予約語: let, in, where Operator(&'a str), // 演算子: +, ++, == Punctuation(char), // 記号: (, ), [, ] OpenBrace, // { (自動挿入) CloseBrace, // } (自動挿入) Separator, // ; (自動挿入) }
  5. インデント構文 インデント構文はくそ 字句解析の段階で自動的に{}, ;を挿入してブロック構造にしインデント構文を解決する qsort [] = [] qsort (x:xs)

    = qsort smaller ++ [x] ++ qsort larger where smaller = [a | a <- xs, a <= x] larger = [b | b <- xs, b > x] qsort [] = []; qsort (x:xs) = qsort smaller ++ [x] ++ qsort larger where { smaller = [a | a <- xs, a <= x]; larger = [b | b <- xs, b > x] } ↓内部的に”{ }”, “;”を挿入する このインデントでブロックを認識する →
  6. pub enum Expr<'a> { Ident(&'a str), // 変数参照: x Literal(Literal<'a>),

    // リテラル: 42 Nil, // 空リスト: [] Cons(Box<Expr>, Box<Expr>), // リスト構築: x:xs App(Box<Expr>, Box<Expr>), // 関数適用: f x Infix(&'a str, Box<Expr>, Box<Expr>), // 演算子: x + y If(Box<Expr>, Box<Expr>, Box<Expr>), // 条件分岐: if...then...else ListComprehension { .. }, // リスト内包表記 Let { .. }, // ローカル変数定義 }
  7. 演算子 Haskellの演算子は正しくは2引数関数 それぞれに結合優先度と結合の向きがあり、 正しくそれを解釈する必要がある 優先度 高 ↑ Level 10: 関数適用

    (f x) │ Level 9: 合成 (f . g) │ Level 7: 乗除 (*, /) │ Level 6: 加減 (+, -) │ Level 5: 連結 (++) │ Level 4: 比較 (==, <, >=) ↓ Level 0: $演算子 (f $ x) 優先度 低 左結合 1 + 2 + 3 - 4 - 5 => (((1 +2) + 3) - 4) - 5 右結合 1 : 2 : 3 : 4 : [] => 1 : (2 : (3 : (4 : [])))
  8. Hindley-Milner type system • HindleyR.:The principle type-scheme of an object

    in combinatory logic, Transactions of the American Mathematical Society, 146, 29-60 (1969) • MilnerRobin:A theory of type polymorphism in programming, Journal of Computer and System Sciences, 17(3), 348-375 (1978)
  9. 制約の収集 -- "length [] = 0" から: t0 = List(t1)

    -> Int -- lengthはリストを受け取りIntを返す -- "length (x:xs) = 1 + length xs" から: t2 = List(t1) -- xsはxと同じ型のリスト t0 = List(t1) -> Int -- 2つ目の節も同じ型でなければならない
  10. 単一化 あつめた制約を順番に解いていくフェーズ 制約: t0 = List(t1) -> Int t2 =

    List(t1) 解: t0 = List(a) -> Int t1 = a t2 = List(a) 結果: length :: List(a) -> Int
  11. pub fn unify(t1: &Type, t2: &Type) -> Result<Subst, String> {

    match (t1, t2) { (a, b) if a == b => Ok(Subst::new()), // 同じ型 → OK // 片方が型変数 → その変数に型を代入 (Type::Var(name), ty) | (ty, Type::Var(name)) => bind(name, ty), // 関数型同士 → 引数と戻り値をそれぞれ単一化 (Type::Func(l1, r1), Type::Func(l2, r2)) => { let s1 = unify(l1, l2)?; let s2 = unify(&r1.apply(s1), &r2.apply(s1))?; Ok(compose(s2, s1)) } (a, b) => Err(format!("型エラー: {:?} ≠ {:?}", a, b)), } } 引数を2つ受け取って、2つの型が同一であるこ とを確認する 両方同じ型なら解決 片方が型変数なら変数に型を代入 両方関数型であれば、引数と戻り値をそれぞれ 単一化(再帰で解決)
  12. 課題 できること • パターンマッチ • let, where • リスト内包表記 •

    演算子 • if式 • 多相型→ジェネリクス変換 できないこと • 遅延評価 • 型クラス • ラムダ式 • 代数的データ型 • モジュールシステム