Skip to content

型なき言語に付ける型

公開日:

Clusterバーチャル空間で開催された『バーチャル空間勉強会#0』でライトニングトーク(5分)として発表しました。

Download PDF

スライドテキスト

Page 1

型なき言語に付ける型

Type in untyped languages

#virtual_study_groupバーチャル空間勉強会#0

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE
  • GitHub/Packagistでは id: zonuexe
  • ピクシブ株式会社 pixiv運営本部
  • Emacs Lisper, PHPer, Rubyist
  • Emacs PHP Modeのメンテナ引き継ぎました
  • 好きなリスプはEmacs Lispです
  • Qiitaに記事を書いたり変なコメントしてるよ

Page 3

Page 4

Page 5

近況

Page 6

Page 7

Page 8

話しました

Page 9

Page 10

Page 11

Page 12

仕方がないので全然違う話をします

Page 13

本日のお題

Page 14

型、ついてますか?

Page 15

型については結構雑な印象で見解を語るひとが多い

Page 16

俺も俺も

Page 17

型があるから変更に強いというひとも居れば、型がないから変更に強いというひとも居る

Page 18

???

Page 19

型よくわからん

Page 20

私もだ

Page 21

intとboolとかでしょ

Page 22

Page 23

読むがよい

Page 24

‒Benjamin C. Pierce 著/住井英二郎 監訳/遠藤侑介・酒井政裕・今井敬吾・黒木裕介・今井宜洋・才川隆文・今井健男 訳 『型システム入門 プログラミング言語と型の理論』(オーム社、978-4-274-06911-6、2013年)サンプル

Page 25

‒Benjamin C. Pierce 著/住井英二郎 監訳/遠藤侑介・酒井政裕・今井敬吾・黒木裕介・今井宜洋・才川隆文・今井健男 訳 『型システム入門 プログラミング言語と型の理論』(オーム社、978-4-274-06911-6、2013年)サンプル

Page 26

(一章はサンプルとしてPDFが無料でダウンロードできます)

Page 27

正しい、完璧に正しいのだが

Page 28

最初から用語多すぎ

Page 29

説明の抽象度が高すぎて現実とのギャップ大きすぎ

Page 30

この1章の内容を解きほぐして説明するだけで何時間も話せそう

Page 31

そのほかの型とかプログラミング言語論の本を読むと数式みたいなのが出てきてワケワカラン

Page 32

型についてちょっと知りたいだけなのに

Page 33

世の中の人と型

Page 34

型を使っているが思索の対象として向き合ってないひと

Page 35

特定の言語の型とだけ向き合ってる人

Page 36

抽象概念の型と向き合ってるひと

Page 37

いろんな背景の人が居る

Page 38

動的言語を使っていると静的型付き言語利用者から冷ややかに見られがち

Page 39

やーい型なし型なし

Page 40

型はあるんだ!実行時にあるんだ!

Page 41

そういうことをまじめに主張すると憐れみを湛えた目で見られはじめる

Page 42

真の型なし言語も複数あるが今回は割愛しました

Page 43

型わかりたくないですか

Page 44

このトークに結論はない

Page 45

実際の言語の型からいきましょう

Page 46

C言語

Page 47

よくわからんけど型がだるい

#include <stdio.h>

long add(long a, long b) {return a + b;}

int main(void) {unsigned int x = 1, y = 2;

printf("%d + %d = %d\n", x, y, add(x, y));}

Page 48

私たちFラン情報科学生は情弱なのでまともな説明もないカビの生えた教科書でC言語を叩き込まれる

Page 49

私の入門者時代のC言語理解は曖昧なので曖昧なままで次の話に進めます

Page 50

さておき

Page 51

短くなってべんり

// JavaScript

function add(a, b) {return a + b;}

const x = 1, y = 2;

console.log(`${x} + ${y} + ${add(x, y)}`);

Page 52

もっと短くなってべんり

# Ruby

def add(a, b)a + b end

x = 1; y = 2

puts "#{x} + #{y} + #{add x, y}"

Page 53

そういう俺たちが動的言語に触れるとこうなる

Page 54

型とか要らんやろw

Page 55

そうだな

Page 56

見ればわかるだろ

# Ruby

# to_sオブジェクトが生えてたら何でもいい

def show(obj)puts obj.to_s end

Page 57

常識的に考えて

# Ruby

# 足し算できるものならなんでもいいし

# ジェネリクスとかなくてもいいw

def add(a, b)a + b end

def show(obj)puts obj.to_s end

Page 58

引数が少ないうちはな…

# Ruby

user = User.findBy(id: params[:user_id])

Page 59

引数が増えてくると

# Ruby

obj = palpunte(user_id,????,????,????,)

p obj

Page 60

実装を直接見に行く機会が増える

Page 61

引数が増えてくると

# Ruby

# 実装を見ないと期待するオプションに何を渡せばいいのか

def palpunte (id, foo, bar, buz)p [id, foo, bar, buz]end# というか見てもよくわからない

Page 62

素朴に書くと引数がわからん

# Ruby

# 実際にはキーワード引数だけで表現できる

def palpunte (id: nil, **options)raise TypeError if id.nil?

foo ||= "default foo"bar ||= "default bar"buz ||= "default buz"

p [id, foo, bar, bar]]end

Page 63

だんだん型チェックが増えてく

# Ruby

raise TypeError unless foo.instance_of?(String)raise TypeError unless bar.instance_of?(String)raise TypeError unless buz.instance_of?(String)

Page 64

いわゆる動的言語にも型が付く流れ

Page 65

Flowtype

TypeScript

Page 66

PEP484

mypy

Page 67

Ruby3 rbi

Sorbet

Steep

Page 68

PHP型宣言

PHPDoc

PhpStorm,Phan

Page 69

身体は型を求める

Page 70

型が付いていないということはどういうことか

Page 71

可能性は無限大

<?php

/*** @param mixed $a 可能性は無限大

* @param mixed $b* @return mixed*/function add($a, $b){return $a + $b;}

Page 72

仮引数宣言がない言語

<?php

function add(){$args = func_get_args();

return array_pop($args)+ array_pop($args);}

Page 73

無限大じゃ困るんだよ

Page 74

とはいえ+できる値という前提があるので案外困らない

Page 75

ほんとに?

Page 76

PHPの演算子の暗黙的型変換

<?php

error_reporting(0);

var_dump(add(1, 2)); // => int(3) 想定通り

var_dump(add(1.0, 2.0)); // => float(3.0) 許容範囲

var_dump(add('1', '2')); // => int(3) 許容範囲

var_dump(add('', '')); // => int(0) ?????var_dump(add(1, 2, 3)); // => int(3) ?????var_dump(add([], [])); // => [] えっ?????

var_dump(add(PHP_INT_MAX, 1));// => float(9.2233720368548E+18)

Page 77

実行時に型を調べよう

Page 78

いわゆる動的言語は実行時に型があるのでそれを検査できる

Page 79

JavaScriptではtypeof 演算子で型名文字列がとれる

Page 80

Python type()

Ruby Object#class

Page 81

PHPではis_int(),is_string()などの関数(gettypeは使いにくい)

Page 82

可能性を絞り込もう

<?php

/*** @param mixed $a 可能性は無限大

* @param mixed $b 可能性は無限大

* @return mixed*/function add($a, $b){if (!is_int($a)) {throw new TypeError('Error');}if (!is_int($b)) {throw new TypeError('Error');}

// 実装するときに int 以外の値が渡ってくる可能性を考えなくて良い

return $a + $b;}

Page 83

実行時に変な値に対して処理が続行する可能性は避けられる

Page 84

例外で処理が停止するので

Page 85

PHPとかいう静的型付きプログラミング言語

Page 86

静的型付きPHP

<?php declare(strict_types=1);

// このメソッドを実装するときに int 以外の値が

// 渡ってくる可能性は考えなくてよい

function add(int $a, int $b): int{return $a + $b;}

Page 87

静的 =実行しなくても型が決まってる状態

Page 88

静的型付きStatically typed既に型が決定してる

Page 89

動的型付けDynamic typing実行時に型を付ける

Page 90

よくある誤解

静的型=コンパイラ

動的型=インタプリタ

Page 91

ただしプログラム実行時のデータの表現方法がそういう関係になりがち

Page 92

C言語は静的型付き

Page 93

多くの動的言語はC言語で実装

Page 94

必ずしも排他の関係ではない

Page 95

お使いの言語ランタイム(ruby,python, phpなど)のC言語実装がどうなっているか、変数がC言語の型でどう表現されてるか読んでみるとおもしろいと思います

Page 96

PHPは実行時に型をチェックする

Page 97

ただし関数とプロパティに静的に型を付けられる

Page 98

ただし静的に型を付けても実行時にクラッシュする可能性があります

Page 99

型で守られてるとはどういう状態か

Page 100

‒Akinori Abe 『型安全性入門』(Apr 6, 2017)

Page 101

‒Akinori Abe 『型安全性入門』(Apr 6, 2017)

Page 102

関数を呼び出す側が間違って呼び出すことをPHPだけでは防げない

Page 103

動的言語で完全かつ健全にするのは不可能

Page 104

偽陽性(動かないのに動きそうなフリをしている)ことを最小にしていくことを目指す

Page 105

コンパイラの代りに静的型チェッカーを使おうということになる

Page 106

PHPでも複数の型チェッカーが揃っている

Page 107

PhpStorm

Phan, Psalm

PHPStan

Page 108

PHPのソースコードを解析しても判別できない型は注釈(annotate)してあげる必要がある

Page 109

人間がコメントで型を書く

Page 110

人間が型を間違ってつけると破綻するので実際簡単ではない

Page 111

連想配列(Hash, dict)を構造体のつもりで多用されると静的解析を簡単に破滅できる

Page 112

と思うでしょ?PHPDocでなら型をつけられます

Page 113

PHPに型を付けたりCIに載せる話はFANBOXに記事やスライドを掲載してます

Page 114

Page 115

型について学ぶにはどうすればいい

Page 116

Page 117

ハードルが高い(そもそも値段が…)

Page 118

一章のPDFは無料なので読んでほしいが難しいので理解できなくてもいい

Page 119

Page 120

型のみならずプログラミング言語についてのさまざまな概念を学べる

Page 121

まとめ

Page 122

仕事で使ってる言語を好きになるために目を逸らさず向き合っていこう