Haskell単語


ニコニコ動画でHaskellの動画を見に行く
ハスケル
4.4千文字の記事
  • 7
  • 0pt
掲示板へ

Haskellとは、純関数型プログラミング言語の一種である。

 

概要

Haskellという言語名は論理学者Haskell B. Curry名前が由来。純関数型言語の標準化を的として制定されたといわれている。

静的型付けコンパイラ言語で、型推論が利用できるため関数変数宣言を省略することがある程度は可である。プログラムの記述は、「等式の左辺は右辺の式へと変換できる」という関係性の定義を列挙していく形になる。

型付け以上に特筆すべきなのは関数型言語ということである。Haskellにおける「関数」とは、数学における「関数」と同じく、引数の値が関数の返り値と一意に対応し不変であるものに限定される。関数が内部状態を持つことは許可されない。変数の初期値は再代入によって変更することはできない。このような制約を持つため、プログラムの各部分の実行順序を任意に選ぶことができ、今後並列演算への応用も期待できる。

Haskellにおいて、標準入出力を用いた処理など純な(数学における)関数表現では実現できない処理は「アクション」と呼ばれ「関数」とは区別しているが、両者を同一プログラム内で矛盾を起こさないように共存させる仕組みが提供されている。

変数関数スコープは、中括弧などコードブロックを囲むような記号は使わず、Pythonなどのようにソースコードインデントの深さで表現される。

遅延評価を採用しており、無限リストを容易に扱うことができる。

実装と開発環境

HaskellのためのフリーコンパイラとしてはGHC(Glasgow Haskell Compilerexit)がデファクトスタンダードで、Stackexitと一緒についてくる。他にはHugsexitなどがある。これらのコンパイラEclipseからも利用することもできたが、現在プラグインEclipse FPと連携するパッケージ依存関係の変化に対応できず開発中止になっている。他の統合開発環境パッケージ依存関係を解決できなくてインストールもままならないことが多く、フリー開発環境はもっぱらテキストエディタが中心になる。

マイナー実装だが、Java仮想マシン向けにFregeexitEtaexitという実装が存在する。前者はJavaコードトランスパイルされ、後者Java仮想マシン用中間バイトコードコンパイルされる。両者ともJavaライブラリが利用可だが、Javaから持ち込まれたクラスの扱い方は異なっている。

用途

間違いが発生しにくいとか、数学と相性が良いなどの理由からか、数字の計算に終始する金融投資関係での利用が多いといわれている。

参照透過性とGUIとは相性が悪いのでゲーム開発には適さないと考えられているが、Haskellで書かれた日本で有名なゲームMonadiusexitというのがあり、開発不可能ということはない。(GUIの処理ははOpenGLを利用したライブラリGLUTによるもの)

純粋関数型言語

Haskellは関数型言語の中でも、関数や再代入による状態変更を副作用として排除するを選んだ関数型言語である。

プログラミングスタイルとしては、その特性を活かして実行順序に関係なく、関係性の定義を宣言的に記述していくことで自動的に結果が導き出される宣言型プログラミングが推奨されている。従来のプログラミング言語とは全く違うその発想に、いわゆる命プログラミングしんできた人が接すると、拒絶反応を起こすか熱心な信奉者になるかに二極化するらしい。

プログラミング言語が車だったら」のHaskellの項exitより選択抜

モナド

先述のようにHaskellが属する純関数型言語というのは副作用を排除するを選んだ言語である。副作用とは再代入のように状態を変更することである。それくらいならたいした問題ではないのだが、たとえば「画面に文字を表示する」という通常のプログラミング言語ではごく基本的なことに分類されることでも、Haskellでは画面の「状態の変更」であるとみなされる。

従って、純関数型言語であるためにはひたすら計算のみを行い結果の画面表示すら行わないという滑稽な状態にならざるをえない。もちろん、こんなことでは使い物にならないのでHaskellはモナドという仕組みを利用している。IOモナドというものがあり、副作用IOモナドの処理に分離することにより、IOモナドの内部で純関数型言語であり続けるのである。

モナドはHaskellにとって副作用を起こすために必要なものではあったが、副作用を起こす以外にも様々な用途のモナドがあり、いわゆるぬるぽの対処をするMaybeモナドが代表的。さらにはListまでもがモナドとして提供されている。

擬人化するなら

Haskellを擬人化するなら、以下のような感じだろうか。

すべての家具が造り付けで固定された部屋の中に引きこもる潔症の数学少女部屋から出ないので近眼のメガネ属性。外部とのやりとりは、にあいたIOモナドという小さなから行う。

期限が来てからでないと仕事を始めない彼女のことを怠け者と評する人もいるが、その評価は正格ではない。すべてのものが固定された彼女部屋には予めすべてのものがあるべき場所に「ある」のだから、必要になったときに手を伸ばせば事足りるのだ。これを可にするために常日頃から部屋完璧に整理整頓している彼女は、怠け者ではなく地な努力なのである。だが引きこもりだ。

コード表記の例など

Hello worldの例

    main = putStrLn "Hello world!"

Haskellにおいて、文字列(String)は文字Char)のリストとして扱う。リストは列挙した要素群を'['と']'で囲み、各要素の間は','で区切る。
文字列"Hello world!" は文字リスト ['H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'] と同じもの。

右辺は「直前の状態から、"Hello world!"と画面に表示された状態を計算して作り出す関数」という「値」(Haskellは関数も数値と同じく参照透過な値)である。

Schemeにおけるリスト表現で、

(1 . (2 . (3 .(4 . ()))))

と 

(1  2  3  4)

が同一のリストを表わすように、

Haskellでは、

1 : (2 : (3 : (4 : [])))    ※丸括弧省略して、 1 : 2 : 3 : 4 : [] と書いてもよい

と 

[1, 2, 3, 4]

は同一のリストを表わす。 

Schemeのコード表記との比較例

 (記号「→」以降に式の評価結果を記す)

コードの説明 Haskell Scheme
リストの先頭要素取り出し
head  [1, 2, 3]
→ 1
(car  '(1 2 3))
→ 1
リストの先頭要素を除いた残り部分の取り出し
tail  [1, 2, 3]
→ [2, 3]
(cdr  '(1 2 3))
→ '(2 3)
リストに先頭要素を追加
1 : [2, 3]
[1,2,3]
(cons 1 '(2 3))
→ '(1 2 3)
リスト判定
null  []
True
(null?  '())
#t 
関数を使った演算
(\x  y  ->  x + y)  1  2
→ 3
((lambda  (x  y) (+ x  y)) 1  2)
→ 3

自然数nの階乗 n ! を求めるコードの例

繰り返し処理は、他言語によくあるforループのようなものではなく再帰呼び出しや高階関数を使った手法で書くのがHaskellなど関数型言語の基本的な流儀。

-- 同名の関数定義を複数用意して、引数によるパターンマッチングを利用する例

factorial :: Int -> Int   -- 関数名はfactorialとし、引数は整数の値一つ取る、返り値も整数型の値
factorial 0 = 1                       -- 引数が0の場合、返り値は1とす
factorial n = n * factorial (n - 1)   -- 引数が0以外の場合は再帰呼び出しを使って返りを求める

-- 条件式if使った例

factorial :: Int -> Int   
factorial n =
        if n == 0              -- Haskell2010の規定により then/else節のデントは揃えなくてもよい
        then 1    -- 引数nが0の場合、返り値は1とする     else n * factorial (n - 1) -- それ以外の場合は再帰呼び出し使って返り値を求める
-- ガード節を使った例

factorial :: Int -> Int
factorial n
        | n == 0     = 1                          -- 引数nが0の場合、返り値は1とする
        | otherwise = n * factorial (n - 1)     -- それ以外の場合は再帰呼びしを使って返り値を求める

-- case構文パターンマッチングを使った例

factorial :: Int -> Int
factorial n = case n of 
0 -> 1 -- 引数nが0の場合返り値は1とする _ -> n * factorial (n - 1) -- それ以外の合は再帰呼び出しを使って返り値を求める

同様の計算を再帰呼び出しを使わないで行うコードの例

-- 1からnまでの整数リストを生成してその要素をすべてかけ算する例
-- 高階関数 foldl は、第2引数「1」と第3引数整数リストの全要素を使って第1引数の「*」関数を適用 factorial :: Int -> Int factorial n = foldl (*) 1 [1..n] -- 具体的には、1 * (1 * 2 * 3 ....* n) の演算が行われる

関連項目

参考外部リンク

  • 7
  • 0pt
記事編集 編集履歴を閲覧

ニコニ広告で宣伝された記事

この記事の掲示板に最近描かれたお絵カキコ

この記事の掲示板に最近投稿されたピコカキコ

ピコカキコがありません

Haskell

29 ななしのよっしん
2021/05/23(日) 03:10:18 ID: 8IbiZXUzPt
Haskellから受ける、ただでさえ陰キャの多いプログラミング界隈の中でひと際立つキモオタがブヒつきながら触っていそうという印は間違っていない。
その上で、別に数学を極めてなくても使えるし、Haskellコミュニティには優しく教えてくれるおじさんがたくさんいるのでもっと気軽に入門して欲しいということを宣伝しておきたい。
https://haskell.jp/exit
👍
高評価
0
👎
低評価
30 ななしのよっしん
2021/08/27(金) 02:13:45 ID: yjaPULFG9x
> 日本語でおk
ここおかしくね?
自分は文字リテラル内部でもソースコードでも(日本語特有のの概念(ガ格とか)を使うので)日本語使ってるけど支障ないぞ。
Haskell 2010以前の話かな?
👍
高評価
0
👎
低評価
31 ななしのよっしん
2021/08/27(金) 02:19:02 ID: yjaPULFG9x
>>13
みたいなことは今でも起きるけど、文字リテラル内部で書くのには支障はいし、日本語文字列処理はText普通に出来るし、そもそもCharはUCSだしなあ。
日本語表示でたまにエンコディングされた出力が出てウッってなることはあるけど、自分で書く分には適切なテキスト表示関数を使えば困らない。
👍
高評価
0
👎
低評価
32 ななしのよっしん
2021/08/27(金) 02:23:49 ID: 9fgvHqZMgt
>>19
言い得て妙だな
Elmを使う方が数倍良い
👍
高評価
0
👎
低評価
33 ななしのよっしん
2021/09/04(土) 01:53:00 ID: oUjOhjOW/h
Haskellで作られたプログラムで広く人口に膾した
(大抵のLinuxディストリにパッケージがあるとかそういうレベル)ものっていえばなんだろう
とりあえずPandocHaskellだけど
👍
高評価
0
👎
低評価
34 ななしのよっしん
2021/09/15(水) 17:34:59 ID: YcW5DE5QT4
xmonad(小)
👍
高評価
0
👎
低評価
35 ななしのよっしん
2022/09/01(木) 12:57:03 ID: k/zNmD13q6
わからないということがわかった
👍
高評価
0
👎
低評価
36 ななしのよっしん
2022/09/01(木) 21:13:50 ID: 5m5lChVlZ3
👍
高評価
0
👎
低評価
37 ななしのよっしん
2022/09/01(木) 23:45:41 ID: dZjZffplrS
プログラミング言語選択ガイド書いた人と同じ人やね
お察し
👍
高評価
1
👎
低評価
38 ななしのよっしん
2022/09/05(月) 23:30:10 ID: OTgL60Tghp
曲がりなりにも事典なんだし著者の主観書くべきじゃない…
というかウィキ私物化はするべきではないね。
は共有資材であるというウィキというシステム理念的にも。

noteかなにかに書けばいいんじゃないって思う。
👍
高評価
3
👎
低評価

ニコニコニューストピックス