---
title: 純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
tags:  #関数型プログラミング #lisp #clojure #elixir #scala #haskell  
author: [Kent OHASHI](https://convert.docswell.com/user/lagenorhynque)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/47ZKWDML73.jpg?width=480
description: 純LISPのミニマルなデータ構造とオペレータの観点から現代の関数型言語について探ってみよう!
published: March 27, 25
canonical: https://convert.docswell.com/s/lagenorhynque/582Q42-functional-language-primitives-from-the-perspective-of-pure-lisp
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/47ZKWDML73.jpg)

純LISPから考える
関数型言語のプリミティブ
Clojure, Elixir, Haskell, Scala
#lispmeetup
1


# Page. 2

![Page Image](https://bcdn.docswell.com/page/YJ6QG1NMJV.jpg)

🐬カマイルカ
lagénorhynque
株式会社スマートラウンドのシニアエンジニア
スタートアップの起業家と投資家のための業務効
率化/連携プラットフォームを開発している
主要技術スタック: Kotlin &amp; TypeScript
Server-Side Kotlin Meetupの運営企業
関数型プログラミング(言語)とLispの熱烈な愛好者
仕事や趣味でClojure, Scala, Haskellなどに長く
触れてきた(JVM言語の割合高め)
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/GJ5RV45Q74.jpg)

[PR]
カンファレンス「関数型まつり2025」6月開催
近日中にセッションリスト公開、チケット販売予定
企業/個人スポンサー募集中
Lisperの皆様もぜひご検討ください🙏
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/LE3PDGNZJ5.jpg)

関数型言語テイスティング: Haskell, Scala, Clojure,
Elixirを比べて味わう関数型プログラミングの旨さ
取り上げる予定の4つの関数型言語について、Lispの
観点から改めて探ってみるのが今回のテーマ
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/8EDLP1W4JG.jpg)

純
関数型言語Clojure, Elixir, Haskell, Scala
つの言語でのリストとオペレータ
つの言語での高階関数の再実装
1. LISP
2.
3. 4
4. 4
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/V7P2NQ9V78.jpg)

純LISP
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/2JVDK5MRJQ.jpg)

とは
&quot;list processing&quot;に由来する言語群
⭐ リストを中核とした言語
重要な特徴
S式(S-expression)
同図像性(homoiconicity)
⭐ 関数型言語(のプロトタイプ)
LISPからLisp族とML族へ
高度なREPL開発環境
[IMO] Lisp
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/5EGYQ6G6EL.jpg)

のリスト内包表記はチューリング完全だから純
だって実装できる by t-sin &gt; 純LISPって？
Python
LISP
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/4JQMK4X27P.jpg)

コンスセル(によるリスト)とその操作
純LISP
現代の言語での表現例
コンスセル構造 (連結)リスト, タプル, レコード
空値/偽値 nil 空リスト, nil/null, false
コンスセル構築 cons/:, リスト/タプル/レコー
cons
ドリテラル
コンスセル分解 head, tail, パターンマッチン
car, cdr
グ
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/K74VPQ6PJ1.jpg)

その他の基本オペレータ
純LISP
現代の言語での表現例
アトム判定 atom 型判定述語
等価判定 eq
==, eq
条件式 if, cond if, match
ラムダ式 lambda =&gt;, -&gt;
定義式 define def, =
クォート quote (非Lisp系言語では稀)
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/LJ139PVX7G.jpg)

関数型言語Clojure, Elixir,
Haskell, Scala
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/GJWPQ2LK72.jpg)

Clojure
paradigm FP
typing
first
appeared
related
&#039;s note
🐬
Elixir
FP
Haskell
FP
dynamic
2007
Scala
OOP,
FP
dynamic static
2012
2004
Lisp
modern
functional
Lisp
Lisp
Erlang +
Ruby +
Clojure
ML
lazy/pure
FPL
standard
ML
OOPL
in
FPL&#039;s
skin
static
1990
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/4EZKWDMNE3.jpg)

つの言語でのリストとオペレータ
4
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/Y76QG1N97V.jpg)

リスト(類似コレクション)のリテラル: Clojure
連結 リスト
クォートにより要素は評価されない
空リスト
値
;; ベクター
;; (
)
&#039;(1 2 3) ;
(list 1 2 3)
() ;
nil ; nil
[1 2 3]
(vector 1 2 3)
[] ;
空ベクター
;; シーケンス(論理的なリストのインターフェース)
(seq [1 2 3]) ; この例ではベクター由来
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/G75RV45DE4.jpg)

リスト(類似コレクション)のリテラル: Elixir
連結 リスト
空リスト
# タプル
{1, 2, 3}
{} # 空タプル
# (
)
[1, 2, 3]
[] #
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/9J2D3VGMJR.jpg)

リスト(類似コレクション)のリテラル: Scala
連結 リスト
// (
)
List(1, 2, 3)
List(), List.empty
Nil // nil
ベクター
値
//
//
Vector(1, 2, 3)
Vector(), Vector.empty
空リスト
空ベクター
// (リストやベクターを含む)シーケンシャルコレクションのインターフェース
//
Seq(1, 2, 3)
タプル
//
(1, 2, 3)
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/DEY213VPEM.jpg)

リスト(類似コレクション)のリテラル: Haskell
連結 リスト
空リスト
-- タプル
-- (
)
[1, 2, 3]
[] -(1, 2, 3)
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/VJN82VMM78.jpg)

リスト(類似コレクション)の構築・分解: Clojure
user=&gt; (cons 1 (cons 2 (cons 3 ())))
(1 2 3) ;
user=&gt; (-&gt;&gt; () (cons 3) (cons 2) (cons 1))
(1 2 3) ;
user=&gt; (conj () 3 2 1)
(1 2 3) ;
/
user=&gt; (conj [] 1 2 3)
[1 2 3] ;
シーケンス
シーケンス
リスト シーケンス
ベクター
; threading macro
user=&gt; (first [1 2 3])
1
user=&gt; (rest [1 2 3])
(2 3) ;
;;
user=&gt; (let [[x &amp; xs] [1 2 3]]
[x xs]) ;
[1 (2 3)]
ベクター由来のシーケンス
分配束縛
ベクターをタプルのように使ってまとめて確認
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/YE9K16NWE3.jpg)

リスト(類似コレクション)の構築・分解: Elixir
iex(1)&gt; [1 | [2 | [3 | []]]]
[1, 2, 3]
iex(2)&gt; Tuple.append(Tuple.append(Tuple.append({}, 1), 2), 3)
{1, 2, 3}
iex(3)&gt; {} |&gt; Tuple.append(1) |&gt; Tuple.append(2) |&gt;
...(3)&gt;
Tuple.append(3) #
{1, 2, 3}
パイプ演算子
iex(4)&gt; hd([1, 2, 3])
1
iex(5)&gt; tl([1, 2, 3])
[2, 3]
#
iex(6)&gt; [x | xs] = [1, 2, 3]
[1, 2, 3]
iex(7)&gt; {x, xs} #
{1, [2, 3]}
iex(8)&gt; {a, b, c} = {1, 2, 3}
{1, 2, 3}
iex(9)&gt; [a, b, c] #
[1, 2, 3]
パターンマッチング
タプルでまとめて確認
リストでまとめて確認
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/GE8R4ZKRJD.jpg)

リスト(類似コレクション)の構築・分解: Scala
scala&gt; 1 :: 2 :: 3 :: Nil
val res0: List[Int] = List(1, 2, 3)
scala&gt; Vector() :+ 1 :+ 2 :+ 3
val res1: Vector[Int] = Vector(1, 2, 3)
scala&gt; List(1, 2, 3).head
val res2: Int = 1
scala&gt; List(1, 2, 3).tail
val res3: List[Int] = List(2, 3)
//
scala&gt; val x :: xs = List(1, 2, 3): @unchecked
val x: Int = 1
val xs: List[Int] = List(2, 3)
scala&gt; val ys :+ y = Vector(1, 2, 3): @unchecked
val ys: Vector[Int] = Vector(1, 2)
val y: Int = 3
scala&gt; val (a, b, c) = (1, 2, 3)
val a: Int = 1
val b: Int = 2
val c: Int = 3
パターンマッチング
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/LELK6DZ2JR.jpg)

リスト(類似コレクション)の構築・分解: Haskell
&gt; 1 : 2 : 3 : []
[1,2,3]
it :: Num a =&gt; [a]
&gt; head [1, 2, 3]
1
it :: Num a =&gt; a
&gt; tail [1, 2, 3]
[2,3]
it :: Num a =&gt; [a]
-&gt; x : xs = [1, 2, 3]
x :: Num a =&gt; a
xs :: Num a =&gt; [a]
&gt; (x, xs) -(1,[2,3])
it :: (Num a1, Num a2) =&gt; (a1, [a2])
パターンマッチング
タプルでまとめて確認
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/4JM25PV9JW.jpg)

&gt; (a, b, c) = (1, 2, 3)
a :: Num a =&gt; a
b :: Num b =&gt; b
c :: Num c =&gt; c
&gt; [a, b, c] -[1,2,3]
it :: Num a =&gt; [a]
リストでまとめて確認
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/PJRM3129E9.jpg)

判定述語: Clojure
型判定
;;
user=&gt; (seq? []) ;
false
user=&gt; (seqable? []) ;
true
;;
user=&gt; (seq []) ;
nil
user=&gt; (empty? []) ;
true
;;
user=&gt; (= 1 2)
false
user=&gt; (not= 1 2)
true
空判定
等価判定
シーケンス判定
シーケンス化可能(シーカブル)判定
シーケンス化(nil punningで非空判定)
コレクション/シーケンスの空判定
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/PEXV4YD37X.jpg)

判定述語: Elixir
型判定
#
iex(1)&gt; is_list([]) #
true
iex(2)&gt; is_tuple({}) #
true
#
iex(3)&gt; Enum.empty?([])
true
#
iex(4)&gt; 1 == 2
false
iex(5)&gt; 1 != 2
true
空判定
等価判定
リスト判定
タプル判定
# Enumerable
の空判定
24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/3EKQZ3XNED.jpg)

判定述語: Scala
静的型付き言語なので動的に型判定することは稀
// 空判定
//
scala&gt; List().isEmpty
val res0: Boolean = true
scala&gt; Vector().isEmpty
val res1: Boolean = true
//
scala&gt; 1 == 2
val res2: Boolean = false
scala&gt; 1 != 2
val res3: Boolean = true
等価判定
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/L73PDG5ZE5.jpg)

判定述語: Haskell
静的型付き言語なので動的に型判定することは稀
-- 空判定
--
&gt; null []
True
it :: Bool
-&gt; 1 == 2
False
it :: Bool
&gt; 1 /= 2
True
it :: Bool
等価判定
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/87DLP1D4EG.jpg)

条件式 if
;; Clojure
user=&gt; (if (= 1 2) :t :f)
:f
# Elixir
iex(1)&gt; if 1 == 2, do: :t, else: :f
:f
// Scala
scala&gt; if (1 == 2) &#039;t&#039; else &#039;f&#039;
val res0: Char = f
-- Haskell
&gt; if 1 == 2 then &#039;t&#039; else &#039;f&#039;
&#039;f&#039;
it :: Char
27


# Page. 28

![Page Image](https://bcdn.docswell.com/page/VJP2NQXVJ8.jpg)

ラムダ式(a.k.a. 関数リテラル)
;; Clojure
(fn [x] (* x x))
#(* % %)
;
略記法
# Elixir
fn x -&gt; x * x end
&amp;(&amp;1 * &amp;1)
#
略記法
// Scala
x =&gt; x * x
-- Haskell
\x -&gt; x * x
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/2EVDK5LREQ.jpg)

定義式: Clojure, Elixir
;; Clojure
(def x 42)
(def f (fn [x] (* x x)))
(defn g [x] (* x x))
;
上とほぼ等価な定義(メタデータに差が生じうる)
# Elixir
x = 42
f = fn x -&gt; x * x end
#
defmodule SomeModule do
def g(x), do: x * x #
end
無名関数を束縛した変数
モジュールの名前付き関数
29


# Page. 30

![Page Image](https://bcdn.docswell.com/page/57GYQ6X67L.jpg)

定義式: Scala, Haskell
// Scala
val x = 42
関数オブジェクトを束縛した変数
def g(x: Int) = x * x // メソッド(eta-expansionで上と等価に)
val f = (x: Int) =&gt; x * x
//
-- Haskell
x = 42
f = \x -&gt; x * x
g x = x * x
--
上と等価な定義
30


# Page. 31

![Page Image](https://bcdn.docswell.com/page/4EQMK482JP.jpg)

クォート: Clojure, Elixir
;; Clojure
user=&gt; &#039;(+ 1 2)
(+ 1 2)
# Elixir
iex(1)&gt; quote do: 1 + 2
{:+,
[
context: Elixir,
imports: [{1, Kernel}, {2, Kernel}]
], [1, 2]}
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/KJ4VPQ2PE1.jpg)

つの言語での高階関数の再実装
4
32


# Page. 33

![Page Image](https://bcdn.docswell.com/page/LE139PMXJG.jpg)

高階関数 reduce: Clojure, Elixir
user=&gt; (defn reduce&#039; [f val coll]
(if (empty? coll)
val
(recur f (f val (first coll)) (rest coll))))
#&#039;user/reduce&#039;
user=&gt; (reduce&#039; * 1 [1 2 3 4 5])
120
iex(1)&gt; defmodule MyPrelude do
...(1)&gt;
def reduce([], acc, _), do: acc
...(1)&gt;
def reduce([x | xs], acc, f),
...(1)&gt;
do: reduce(xs, f.(acc, x), f)
...(1)&gt; end
{:module, MyPrelude, ..., {:reduce, 3}}
iex(2)&gt; MyPrelude.reduce([1, 2, 3, 4, 5], 1, &amp;(&amp;1 * &amp;2))
120
33


# Page. 34

![Page Image](https://bcdn.docswell.com/page/GEWPQ23KJ2.jpg)

高階関数 foldLeft: Scala, Haskell
scala&gt; def foldLeft[A, B](list: List[A])(acc: B)
(f: (B, A) =&gt; B): B =
|
if (list.isEmpty) acc
|
else foldLeft(list.tail)(f(acc, list.head))(f)
def foldLeft[A, B](list: List[A])(acc: B)(f: (B, A) =&gt; B): B
scala&gt; foldLeft(List(1, 2, 3, 4, 5))(1)(_ * _)
val res0: Int = 120
&gt; :{
ghci| foldLeft :: (b -&gt; a -&gt; b) -&gt; b -&gt; [a] -&gt; b
ghci| foldLeft _ acc [] = acc
ghci| foldLeft f acc (x:xs) = foldLeft f (f acc x) xs
ghci| :}
foldLeft :: (b -&gt; a -&gt; b) -&gt; b -&gt; [a] -&gt; b
&gt; foldLeft (*) 1 [1, 2, 3, 4, 5]
120
it :: Num a =&gt; a
34


# Page. 35

![Page Image](https://bcdn.docswell.com/page/47ZKWDVN73.jpg)

高階関数 map: Clojure, Elixir
user=&gt; (defn reverse&#039; [coll] (reduce&#039; #(cons %2 %1) () coll))
#&#039;user/reverse&#039;
user=&gt; (defn map&#039; [f coll]
(reduce&#039; #(cons (f %2) %1)
()
(reverse&#039; coll)))
#&#039;user/map&#039;
user=&gt; (map&#039; #(* % %) [1 2 3 4 5])
(1 4 9 16 25)
iex(3)&gt; defmodule MyPrelude do
...(3)&gt;
# def reduce ...
...(3)&gt;
def reverse(list),
...(3)&gt;
do: reduce(list, [], &amp;([&amp;2 | &amp;1]))
...(3)&gt;
def map(list, f),
...(3)&gt;
do: reduce(reverse(list), [], &amp;([f.(&amp;2) | &amp;1]))
...(3)&gt; end
{:module, MyPrelude, ..., {:map, 2}}
iex(4)&gt; MyPrelude.map([1, 2, 3, 4, 5], &amp;(&amp;1 * &amp;1))
[1, 4, 9, 16, 25]
35


# Page. 36

![Page Image](https://bcdn.docswell.com/page/YJ6QG159JV.jpg)

高階関数 map: Scala, Haskell
scala&gt; def reverse[A](list: List[A]): List[A] =
|
foldLeft(list)(List())((acc, x) =&gt; x :: acc)
def reverse[A](list: List[A]): List[A]
scala&gt; def map[A, B](list: List[A])(f: A =&gt; B): List[B] =
|
foldLeft(reverse(list))(List())((acc, x) =&gt;
|
f(x) :: acc)
def map[A, B](list: List[A])(f: A =&gt; B): List[B]
scala&gt; map(List(1, 2, 3, 4, 5))(x =&gt; x * x)
val res1: List[Int] = List(1, 4, 9, 16, 25)
&gt; :{
ghci| reverse&#039; :: [a] -&gt; [a]
ghci| reverse&#039; = foldLeft (flip (:)) []
ghci| map&#039; :: (a -&gt; b) -&gt; [a] -&gt; [b]
ghci| map&#039; f = foldLeft (\acc x -&gt; f x : acc) [] . reverse&#039;
ghci| :}
map&#039; :: (a -&gt; b) -&gt; [a] -&gt; [b]
reverse&#039; :: [a] -&gt; [a]
&gt; map&#039; (\x -&gt; x * x) [1, 2, 3, 4, 5]
[1,4,9,16,25]
it :: Num b =&gt; [b]
36


# Page. 37

![Page Image](https://bcdn.docswell.com/page/GJ5RV4YD74.jpg)

高階関数 filter: Clojure, Elixir
user=&gt; (defn filter&#039; [pred coll]
(reduce&#039; (fn [acc x] (if (pred x) (cons x acc) acc))
()
(reverse&#039; coll)))
#&#039;user/filter&#039;
user=&gt; (filter&#039; odd? [1, 2, 3, 4, 5])
(1 3 5)
iex(5)&gt; defmodule MyPrelude do
...(5)&gt;
# def reduce ...
...(5)&gt;
# def reverse ...
...(5)&gt;
def filter(list, pred),
...(5)&gt;
do: reduce(reverse(list), [], fn acc, x -&gt;
...(5)&gt;
if pred.(x), do: [x | acc], else: acc
...(5)&gt;
end)
...(5)&gt; end
{:module, MyPrelude, ..., {:filter, 2}}
iex(6)&gt; require Integer
Integer
iex(7)&gt; MyPrelude.filter([1, 2, 3, 4, 5], &amp;Integer.is_odd/1)
[1, 3, 5]
37


# Page. 38

![Page Image](https://bcdn.docswell.com/page/9E2D3VYMER.jpg)

高階関数 filter: Scala, Haskell
scala&gt; def filter[A](list: List[A])(pred: A =&gt; Boolean):
List[A] =
|
foldLeft(reverse(list))(List())((acc, x) =&gt;
|
if (pred(x)) x :: acc else acc)
def filter[A](list: List[A])(pred: A =&gt; Boolean): List[A]
scala&gt; filter(List(1, 2, 3, 4, 5))(_ % 2 != 0)
val res2: List[Int] = List(1, 3, 5)
&gt; :{
ghci| filter&#039; :: (a -&gt; Bool) -&gt; [a] -&gt; [a]
ghci| filter&#039; pred = foldLeft (\acc x -&gt;
ghci|
if pred x then x : acc else acc) [] . reverse&#039;
ghci| :}
filter&#039; :: (a -&gt; Bool) -&gt; [a] -&gt; [a]
&gt; filter&#039; odd [1, 2, 3, 4, 5]
[1,3,5]
it :: Integral a =&gt; [a]
38


# Page. 39

![Page Image](https://bcdn.docswell.com/page/D7Y213GP7M.jpg)

まとめ
純LISP相当のデータ構造とオペレータは現代の関数
型言語でも重要な役割を果たしている
コレクション操作は関数型プログラミングの基盤
のひとつだといえる
関数型言語の入門時に最初に探るのもオススメ
リストに対する最小限のオペレータからボトムアッ
プにライブラリを充実させることができる
実際の標準ライブラリではより効率的かつ汎用的
に実装されている(はず)
39


# Page. 40

![Page Image](https://bcdn.docswell.com/page/VEN82VGMJ8.jpg)

Further Reading
Clojure: https://clojure.org/
Elixir: https://elixir-lang.org/
Scala: https://www.scala-lang.org/
Haskell: https://www.haskell.org/
: Reimplementation of typical
higher-order functions in Clojure, Elixir, Scala and
Haskell
サンプルコード
40


