Skip to content

Instantly share code, notes, and snippets.

@pasberth
Created April 18, 2014 13:27
Show Gist options
  • Select an option

  • Save pasberth/11044266 to your computer and use it in GitHub Desktop.

Select an option

Save pasberth/11044266 to your computer and use it in GitHub Desktop.
関数型言語の好きなところ

関数型言語の好きなところ

代数的データ型

いわゆる Haxe の enum というやつ。 これがないとプログラミングできない。

たとえば、

data Tree a = Node (Tree a) (Tree a) | Leaf a

と書いた場合、これはオブジェクト指向的には

sealed trait Tree[T]
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T]
case class Leaf[T](value: T) extends Tree[T]

こういうものを書いたことになる。 この例は Scala なのでまだ良いけど Ruby の場合

class Tree; end
class Node < Tree
  def initialize(left, right)
    @left = left
    @right = right
  end
end
class Leaf < Tree
  def initialize(value)
    @value = value
  end
end

こんなに書かないといけない、マジで死ぬ

ちなみに CoffeeScript とかだと

class Tree
class Node extends Tree
  constructor: (@left, @right) ->
class Leaf extends Tree
  constructor: (@value) ->

みたいにコンストラクタの引数に @ をつけると その名前で初期化してくれるのでまぁ幸せ、でもやっぱり いちいち extends とかしないといけないのめんどう

C++ ではコロンで区切るとアレしてくれるみたいだけど同じ名前を4回くらい書かないといけない (フィールドの宣言,仮引数の宣言,初期化するフィールドの名前の 指定,初期化する式の指定)くて 死ぬ

@人類 コンストラクタを人間に書かせるな

Immutable が基本であること

mutable なものは人間には扱えない、助けてくれ

データが基本的に immutable であるので、データがどう操作されるのかわかりやすい、 バグりにくい。

Ruby や Python といった言語でもデータを破壊するような 関数やメソッドの使用は、効率的に処理するとき以外はあまりよくない。 (Python でも lst.sort() より sorted(lst)lst.reverse() より reversed(lst) のほうがいいよね?) このことは On Lisp などにも書かれている。

型システムが洗練されている

全体として、オブジェクト指向言語と関数型言語だと、関数型言語の方が 高度な型システムを持っていることが多い。

Lisp のような例外もある。 ちなみにどういうわけか Typed racket や core.typed とか shen みたいに Lisp ではオプショナルで型システムが提供されることが多いみたいだけど使ってる人見たことない。 (静的型システムは不要と考える文化もある)

Maybe がある

TypeScript はすべて nullable 型だ、助けてくれ

どんな型にでも null は代入できるなんて狂った仕様だ。 みんなそんなにヌルチェックが好きなのだろうか?

C++ では生ポインタじゃなくて参照を使う意義はヌルを許容しないからって理由が大きいのだそうだ[要出典] とにかくヌルを型レベルで区別できるようにするのは大事だ。

ミスしにくい

人間がミスしてもコンパイラが怒ってくれることが動的言語やセグフォ/ヌルポしまくるオブジェクト指向言語に 比べて少ない。

変数名を間違えるなんてよくあるミスだし、変数の解決が静的におこなわれない動的言語では それがいつまでも発見されないこともしばしばある (エディタの補完? それじゃ不十分だ、入力が曖昧だったとき 誤った名前が補完されてそれに気づかないこともある)

眠いときは完全に間違った +goto fail; goto fail;+ なんてコードもよく書く

もちろん完全にミスをなくせるわけではないけど、ミスしにくいというのは重要な要素だ。

手続き的にも書ける

関数型erがいつも再帰とか使って関数型チックなコードを書いてるわけじゃないし、むしろ、 Maybe/Either による例外のような広域脱出、 Control.Monad.Trans.Loop による break/continue とかを使ったコード、 ref (ocaml) や IORef で書き換え可能なローカル変数を使ったり、 Control.Monad.Reader Control.Monad.State とかでちょっとしたグローバル変数 (Reader のほうは const グローバル定数で、 State は mutable グローバル変数をつくれる)を使って、 手続き的にコードを書くこともよくある。というかたぶんそっちのほうが多い。

じゃあなんで 関数型使うのか? っつーと基本的な動機は上に上げた、代数的データ型/immutable な構造/現代的な型システム /Maybe / ミスしにくいみたいなことを動機に使ってる。そういう要素を持つオブジェクト指向言語があればもちろん 関数型じゃなくてオブジェクト指向でもいい(それはScalaのことですね?)、けど基本的にそういう要素を持つ 言語は関数型であることが多いっつー話だ。

プログラミング言語が好きなコミュニティである

関数型言語を好きな人はみんなプログラミング言語が好きだ。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment