独断と偏見によるHaskellの紹介(公開版)

山本悠滋

2016-03-22 Thanks God! It’s Haskell day

※このスライドは、社内勉強会で使ったものを一部加工したものです。
※理由はもう覚えてませんがが書きかけの箇所(「hoge」って書いてるところ)が何カ所かあります。

はじめまして!

私とHaskell

私とHaskell

お話しすること

  1. FAQ
  2. Javaはじめ他の言語との比較
  3. Webアプリの開発と運用
  4. Javaとの連携
  5. 製品での事例紹介

FAQ

Haskellって何に使えるの?

普通に何でも書けます。

Haskellって何に使えるの?

ちょっとしたスクリプトでも、

Haskellって何に使えるの?

Webサーバーでも、

Haskellって何に使えるの?

Wiki engineでも、

Haskellって何に使えるの?

ドキュメント変換器でも、

Haskellって何に使えるの?

静的サイトジェネレーターでも!

どういう形式で実行されるの?

IDEは?

オブジェクト指向っぽいことは?

オブジェクト指向っぽいことは?

(いわゆる、自然に存在するもののアナロジーで)
ふっつーに新しいデータ型を定義できますし、

data Shape =
  Rectangle
    { height :: Double, width :: Double }
  | Circle
    { radius :: Double }

オブジェクト指向っぽいことは?

moduleからexportしないことで、データ構造の隠蔽もできます。

module Shape
  ( Shape -- こっちがpublic
  , publicFuncA
  , publicFuncB
  ) where

-- exportしない方がprivate
func :: Shape -> Foo
func shape = ...

オブジェクト指向っぽいことは?

「型クラス」という、インターフェースと似たものもあります。

class Comparable a where
  compareTo :: a -> a -> Int

オブジェクト指向っぽいことは?

※実際には型クラスを使わずに高階関数をうまく使えば大抵要らない、
という声も聞きますが、まぁやり方は人それぞれで。

Javaはじめ他の言語と比べて良いところ

もっと強く、優しい型

もっと強く、優しい型

数値リテラルまで多相型

10進数が捗る

x :: Double  -- <- ここでDoubleと宣言しているから
x = 1 + 0.1  -- <- ここの2つの数値リテラルはDoubleになる

y :: Decimal -- <- ここでDecimalと宣言しているから
y = 1 + 0.1  -- <- ここの2つの数値リテラルはDecimalになる

影響範囲のコントロール

「純粋な関数」と「イミュータブルな変数」でコードの影響範囲をコントロール!

影響範囲のコントロール

そもそも「純粋な関数」って

影響範囲のコントロール

純粋な関数じゃない・変数がミュータブルだと

影響範囲のコントロール

Result fooResult = null;
// ...
x.setResult(fooResult);

影響範囲のコントロール

変数がイミュータブルだと

let fooResult = ...
-- ...
x { result = fooResult }

影響範囲のコントロール

純粋な関数だと

影響範囲のコントロール

とはいえ…

影響範囲のコントロール

そんな時に使えるの、あります。

とにかく純粋なJavaコード

public int sum(int[] integers) {
    int result = 0;
    for (int i : integers) {
        result += i;
    }
    return result;
}

影響範囲のコントロール

安心してください!純粋ですよ!

影響範囲のコントロール

それを、そのまま翻訳したようなHaskellのコード

sum :: [Int] -> Int
sum integers =
  (flip execState) 0 $ do
    forM_ integers $ \i -> do
      modify (+ i)

影響範囲のコントロール

影響範囲のコントロール

hoge: 前述のコードを色をつけて解説

影響範囲のコントロール

ほかにも…

影響範囲のコントロール

すべてはMonadというインターフェースと、
do記法という構文糖によって実現されます。

影響範囲のコントロール

※詳細は一緒に勉強しましょう! vim(_ _)mer
とりあえず今回はこういうことができる、
ということだけ覚えていただけると!

超軽量なスレッド

Intro to Haskell for Erlangersより:

超軽量なスレッド

圧倒的じゃないか我が軍は

超軽量なスレッド

超細かい最適化機構

超細かい最適化機構(続き)

Javaはじめ他の言語と比べて悪いところ

遅延評価は諸刃の剣問題

Haskellの関数は「必要なときだけ」呼び出される

main = do
  let x = 1 + 2
  y <- getContents
  print x

遅延評価は諸刃の剣問題

この場合、yは必要ないのでgetContentsは実行されず、入力から何も読み込まない! hoge: 試す

遅延評価は諸刃の剣問題

何が嬉しいの?

遅延評価は諸刃の剣問題

main = do
  -- 標準入力を**全部**読んで、
  fileContents <- getContents
  -- 行で分割して、最初の5行だけ取って、
  let ls = take 5 (lines fileContents)
  -- 各行の先頭に"First 5 lines: "とつけて出力
  mapM_ putStrLn (map ("First 5 lines: " ++) ls)

hoge: 試す

遅延評価は諸刃の剣問題

遅延評価は諸刃の剣問題

遅延評価は諸刃の剣問題

IOが絡まない例でも…

遅延評価は諸刃の剣問題

↓のような連想配列があったとして

{
    "a": 1 + 2 + 3 + ...,
    "b": 4 + 5 + 6 + ...,
}

hoge

遅延評価は諸刃の剣問題

遅延評価は諸刃の剣問題

回避方法

やっぱり学習は難しい問題

やっぱり、考え方を改めるのは難しいです。

やっぱり学習は難しい問題

拡張クソ多い

拡張クソ多い

とあるライブラリのソース

拡張クソ多い

!!?

{-# LANGUAGE CPP                        #-}
{-# LANGUAGE ConstraintKinds            #-}
{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE FlexibleContexts           #-}
-- ...
{-# LANGUAGE TypeOperators              #-}

拡張クソ多い

拡張クソ多い

いろんな型の値を同じListに入れたい時問題

Javaでは普通にできる下記のようなこと

CharSequence[] strings = {
    "aaa",
    new StringBuilder("bbb")
};

for (String s: strings) {
    System.out.println(s.charAt(0).toString());
}

いろんな型の値を同じListに入れたい時問題

Webアプリの開発と運用

開発環境の構築

開発環境の構築

なぜstack?

詳細は割愛しますが…

なぜstack?

Webサーバー事情

Webサーバー事情

Webサーバー事情

フレームワークもいろいろありますが個人的に気になっているのを挙げますと

デプロイと監視

デプロイ時は、

デプロイと監視

Apacheなどに載せる場合はwai-handler-fastcgiが正解っぽいです。

デプロイと監視

以下はメモリのお話だけですが監視についても。

Javaとの連携

Message Queueは?

FFIは?

call-haskell-from-anythingというのも見つけました。

Haskellの事例紹介

Haskellの事例紹介

新日鉄住金ソリューションズ

Haskellの事例紹介

新日鉄住金ソリューションズ

同社は金融機関向けの時価会計パッケージ製品「BancMeasure」をHaskellで開発した。HaskellではJavaなどと比べて短い記述が可能なため比較は難しいが、コード行数は約2万3000ステップである。プロジェクト発足時にはJavaのスキルしか持たなかった同社の10人の開発人員が、Haskellの習得期間を含めて約6カ月で製品を完成させた。

Haskellの事例紹介

新日鉄住金ソリューションズ

単体テストの効率も向上させることができた。Haskellはコンパイラによるチェック機能が豊富なため、コンパイルが成功した後は、通常の単体テストで検出するようなバグはほとんど発生しなかったからだ。Javaでは1時間コーディングすると、単体テストやデバッグに1~3時間ほどを要するという。これらを総合し、実装工程だけで比べるとHaskellについて言われている「Javaの10倍の生産性というのは嘘ではないと実感できた」

Haskellの事例紹介

NTTデータ

Haskellの事例紹介

NTTデータ

NTTデータでは、レガシーシステムのリバースエンジニアリングツールの開発においてHaskellを利用しています。レガシーシステムのリバースエンジニアリングを行うには多様なプログラミング言語の解析を行う必要があり、解析対象のプログラミング言語に合わせて、一部の機能を修正したり入れ替えたりすることが多いため、関数型プログラミングの利点を大きく享受できることが理由です。

Haskellの事例紹介

朝日ネット

Haskellの事例紹介

朝日ネット

Haskellの事例紹介

朝日ネット

これから使う予定のテキスト

今回は↓を使います!

これから使う予定のテキスト

これから使う予定のテキスト

まとめ

さらにまとめ

つまり!