Haskell

レイアウト

インデントを揃えることで一つのコードブロックを表す 所属するコードブロックのオフサイドラインよりも深くインデントすると前の行の続きになる 以下はいずれも同じ意味 do foo bar bazdo foo bar bazdo foo bar bazdo { foo bar ; baz }

コメント

-- 一行コメント "--" の後に空白を入れるべし {- ブロックコメント -} ネスト可能 リテレイト形式 Haddock

Haskellの構文

コメント レイアウト if式 パターンマッチ case式 関数定義 let式 where節

"" と []

ghci において、"" を評価した結果は "" であり、 を評価した結果は となる。['a', 'b', 'c'] を評価すると "abc" になるにもかかわらず、である。一瞬何でだろうと思ったが、よく考えてみれば当たり前の話で、[] の型は [a] だが、"" の型は [Char] なのだ…

リスト

x : xs (cons) null xs xs ++ ys (append) 数列表記 ".."を使って等差数列を記述 [1..7] -- [1, 2, 3, 4, 5, 6, 7] ['a'..'e'] -- ['a', 'b', 'c', 'd', 'e'] [1, 3..11] -- [1, 3, 5, 7, 9, 11] [1..] -- [1, 2, 3, 4, ....] [1, 3..] -- [1, 3, 5, 7, ....…

タプル

値の組。例: (1, "hoge") , (True , 't') .. fst :: (a, b) -> a snd :: (a, b) -> b zip :: [a] -> [b] -> [(a, b)] # lengthは短い方に揃えられる unzip :: [(a, b)] -> ([a], [b]) ユニット 0要素のタプル

文字・文字列

Char Charモジュールの関数 テスト( Char -> Bool ) : isAlpha , isLower , isUpper , isAlphaNum , isDigit , isHexDigit , isOctDigit : isSpace , isAscii , isLatin1 , isPrint , isControl 変換 : toLower , toUpper : ord , chr String Haskellでは[Ch…

数値

整数型 Int : 処理系依存。GHCは32bitの符号付整数値 Integer : 範囲制限無し 浮動小数点数型 Float Double リテラル 8進表記: 0o644 (ぜろおー) 16進表記: 0xff (ぜろえっくす) リテラルがInt/Integer または Float/Double のどれに決まるかは文脈依存 数値…

真偽値

data Bool = True | False deriving (Eq, Ord, ...) : not x , x && y , x || y

primitive

第一級の値(first-class value)、変数束縛の対象となるもの 真偽値 ( Bool ) 数値 ( Int, Integer, Float, Double ) 文字 ( Char ) 文字列 ( String = [Char] ) タプル ( (a, b) ) ユニット ( () ) リスト ( [a] ) 関数 ( a -> b )

遅延評価の利点と欠点

利点 不要な計算を減らせる 無限リストが扱える 大抵のことはリスト処理でできる 欠点 評価順序がわかりづらい スタックトレースが意味をなさないためデバッグしにくい

参照透過性

Referential transparency「同じスコープ内では、同じ式はすべて同じ値を持つ」という性質

if を関数として実装

Haskellは必要呼出し、OCamlは値呼出し {- Haskell -} myIf :: Bool -> a -> a -> a myIf True t e = t myIf False t e = e main = myIf True (putStrLn "then") (putStrLn "else") ---------- 実行結果: then (* OCaml *) let myIf c t e = match c with tr…

評価戦略

値呼出し (call by value) => 最内簡約 名前呼出し(call by name) => 最外簡約 必要呼出し(call by need) => 最外簡約かつグラフ簡約 最内簡約 先に引数を簡約してから関数を展開 square (1+3) → square 4 → 4 * 4 → 16 最外簡約 関数を展開してから引数を簡…

四章のまとめ

関数 unwords xs any f xs filter f xs head xs tail xs List.tails xs xs `List.isPrefixOf` ys アクション System.getArgs

fgrep

import System import List main = do args <- getArgs cs <- getContents putStr $ fgrep (head args) cs fgrep :: String -> String -> String fgrep pattern cs = unlines $ filter match $ lines cs where match :: String -> Bool match line = any pre…

echo

{- Haskell -} import System main = do args <- getArgs putStrLn $ unwords args モジュール すべての関数や変数はモジュールに所属する import宣言でインポートする Main module main変数を含むモジュール デフォルトでは、外部にmain変数だけを公開 Prel…

三章のまとめ

関数 map f xs concat xs concatMap f xs replicate n x a == b

map関数

{- Haskell -} map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x:xs) = f x : map f xs (* OCaml *) let rec map f = function [] -> [] | x :: xs -> f x :: map f xs

expand

ver.0(タブを'@'に置換) main = do cs <- getContents putStr $ expand cs expand :: String -> String expand cs = map translate cs translate :: Char -> Char translate c = if c == '\t' then '@' else c 高階関数 引数に関数を取る if式 それ自体が値…

Haskell OCaml 整数 Int int 文字 Char char 文字列 String = [Char] string 真偽値 Bool(True) bool(true) 型aのリスト [a] ([1, 2, 3]) a list ([1; 2; 3]) 型変数 (a, b, c) ('a, 'b, 'c) ※ ()内はリテラルの例多相型: 型変数を含む型 型宣言 {- Haskell …

二章のまとめ

関数 putStr cs putStrLn cs print x length xs take n xs reverse xs lines cs unlines ss words cs アクション getContents

tail

main = do cs <- getContents putStr $ lastNLines 10 cs lastNLines n cs = unlines $ takeLast n $ lines cs takeLast n ss = reverse $ take n $ reverse ss : reverse xs

head

main = do cs <- getContents putStr $ firstNLines 10 cs firstNLines n cs = unlines $ take n $ lines cs 関数定義 関数名 [仮引数列] = 本体 : take n xs , unlines ss

lines/unlines と words/unwords

ghciにて。 Prelude> lines "hoge\nhoge\n\nhoge" ["hoge","hoge","","hoge"] Prelude> unlines ["hoge","hoge","","hoge"] "hoge\nhoge\n\nhoge\n" lines は改行文字を取り除く unlines は最後の要素を含め、全て末尾に改行文字をつける Prelude> words " a…

変数名の慣習

整数n - 整数のリストns 文字c - 文字のリストcs (=文字列)

countline

main = do cs <- getContents print $ length $ lines cs $は左括弧を表す。右結合。 "hoge $ ..." == "hoge (...)" : print x , length xs , lines cs

List

全要素の型は揃っている必要がある OCamlも同様。SchemeやRubyだと(静的な型付けを行わないので)バラバラでも可 文字列=文字のリスト

cat

{- Haskell -} main = do cs <- getContents putStr cs do 式を束ねる。上から順に実行。 オフサイドルール Pythonのようにインデントが意味を持つ " getContentsアクションの結果入力された文字列に変数を束縛する。 : getContents , putStr cs (* OCaml *)…

Hello, World!

{- Haskell -} main = putStrLn "Hello, World!" 変数mainを定義 アクションは、評価することで副作用を起こす。 Haskellプログラム実行 = main変数の評価 : putStrLn cs (* OCaml *) let _ = print_endline "Hello, World!" 見た目は殆ど一対一に対応する