Skip to content

PHP式プログラミング入門

公開日:

オンラインZoom会議で開催された『第二回関数型プログラミング(仮)の会』でライトニングトーク(5分)として発表しました。

Download PDF

スライドテキスト

Page 1

PHP式プログラミング入門

Guide to expression-oriented programming in PHP

USAMI Kenta

2022.01.21

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • 仕事ではPHPという静的型付き関数型プログラミング言語を書いています
  • 趣味ではEmacs Lispという雑草のような生命力*の言語を書いています

(*出典: 『初めての人のためのLISP』)

Page 3

普段はEmacsというLisp専用OSでPHP開発する環境を作ってます

Page 4

こういうバックグラウンドなので関数型よくわからない…

Page 5

map/reduceが関数プログラミングなんでしょ

Page 6

僕はあらゆるループをLispのLOOPマクロで書きたい派なんで…

Page 7

ちなみにLispはElixirと同様に、基本的にreturnを書けません

Page 8

さて

Page 9

PHPってどういう言語

Page 10

PHPはHTMLに書く言語?

<!DOCTYPE html public>

<p>現在は<?= date('%H時%i分%s秒です') ?></p>

Page 11

PHPスクリプト

<?php echo "<!DOCTYPE html public>\n\n";echo "<p>現在は", date('%H時%i分%s秒です'), "</p>\n";

Page 12

こういうノリでWebアプリがサクっと書ける素朴な言語

Page 13

PHPはこんな言語

  • 汎用プログラミング言語 (Webだけではない)
  • 昨今ではHTMLにそのまま埋め込むよりもクラス定義が主体
  • <?php タグの内側のシンタックスはCっぽい
  • C言語っぽい {} を使った制御構造がある
  • 式文が ; で終端する

Page 14

PHPとクロージャ

  • 基本的にレキシカルスコープです

Page 15

PHPとクロージャ

  • 基本的にレキシカルスコープです
  • function ($a, $b) { return $a + $b; } のような無名関数

Page 16

PHPとクロージャ

  • 基本的にレキシカルスコープです
  • function ($a, $b) { return $a + $b; } のような無名関数
  • 外側の変数をキャプチャするには明示が必要

function ($a, $b) use ($c) { return $a + $b + $c; }

Page 17

PHPとクロージャ

  • 基本的にレキシカルスコープです
  • function ($a, $b) { return $a + $b; } のような無名関数
  • 外側の変数をキャプチャするには明示が必要

function ($a, $b) use ($c) { return $a + $b + $c; }

  • PHP 7.4からは fn($a, $b) => $a + $b + $c;
  • 明示しなくても キャプチャできて便利

Page 18

これだけ知ればおもしろいこといろいろできそう

Page 19

ところで

Page 20

世の中にはいろんな制約を課したプログラミングがある

Page 21

セミコロンなしでJavaを書くとか

Page 22

Pythonワンライナーとか

Page 23

$なしでPHPを書くとか

Page 24

https://tadsan.fanbox.cc/posts/329540

Page 25

これはこれでおもしろい

Page 26

(再掲)PHPはこんな言語

  • 汎用プログラミング言語 (Webだけではない)
  • 昨今ではHTMLにそのまま埋め込むよりもクラス定義が主体
  • <?php タグの内側のシンタックスはCっぽい
  • C言語っぽい {} を使った制御構造がある
  • 式文が ; で終端する

Page 27

(再掲)PHPはこんな言語

  • 汎用プログラミング言語 (Webだけではない)
  • 昨今ではHTMLにそのまま埋め込むよりもクラス定義が主体
  • <?php タグの内側のシンタックスはCっぽい
  • C言語っぽい {} を使った制御構造がある
  • 式文が ; で終端する

こいつら目障りじゃないですか?

Page 28

セミコロンレス

Javaでは

Page 29

https://horosora.hatenablog.com/entry/2018/08/03/162147より引用

Page 30

; だけじゃなくて{} も縛りたくない?

Page 31

今回の本題

Page 32

(再掲)PHPはHTMLに書く言語

<!DOCTYPE html public>

<p>現在は<?= date('%H時%i分%s秒です') ?></p>

?> 直前は; を削れる

Page 33

すべての処理を<?= に押し込む

Page 34

できれば一個の<?= に押し込む

Page 35

PHPは式指向プログラミングできる下地はいろいろある

Page 36

PHPの特徴

  • スクリプト言語にありがちな定義せずに代入したら使える変数
  • 代入は式!
  • C言語とほぼ同じ制御構造なので if や while は {} または ; 必須
  • 分岐は条件演算子 $cond ? $then : $else でどうにか
  • ループは array_map(), array_reduce() でどうにか

Page 37

これだけできればチューリング完全であることは自明

Page 38

FizzBuzzを書いてみよう

1から100を改行区切りで出力

<?= implode(range(1, 100), "\n") ?>

Page 39

FizzBuzzを書いてみよう

1から100をFizzBuzzに変換して改行区切りで出力

<?= implode(array_map(fn(int $n): string => [[$n, 'Buzz'],['Fizz', 'FizzBuzz']][$n%3==0][$n%5==0],range(1, 100), "\n") ?>

Page 40

こういうノリでmap/reduceに変形できれば任意の処理が可能

Page 41

パイプライン演算子が欲しくなってくるぜ(Lispならスレッドマクロがあるのに)

Page 42

これはLispですね

Page 43

そう思ったことが私にもありました

Page 44

ある日のこと…

Page 45

https://qiita.com/perpouh/items/807775de16986a956d1c より引用

Page 46

https://qiita.com/perpouh/items/807775de16986a956d1c より引用

Page 47

これはやばい

Page 48

https://qiita.com/perpouh/items/807775de16986a956d1c より引用

文を多用してるのでfn() に置き換え困難

Page 49

この路線の限界

Page 50

array_map/array_reduceはあくまで配列処理

Page 51

無限ループできない

Page 52

旧式のfunctionでは自己再帰可能

変数を参照としてキャプチャしないと

<?php

いけない

$fib = function (int $n) use (&$fib) {return ($n < 2)? 1: $fib($n - 1) + $fib($n -2);};

Page 53

アロー関数(fn)では自己再帰不能

クロージャ作成時にはクロージャ自体は作られてない

<?php

ので束縛できない

$fib = fn (int $n) =>($n < 2)? 1: $fib($n - 1) + $fib($n -2);

Page 54

じゃあどうすればいい

Page 55

そうですね

Page 56

不動点演算子

Page 57

いわゆるYコンビネータ(Zコンビネータ)

Page 58

Zコンビネータ

Page 59

これで勝てる

Page 60

可読性重視版

Page 61

圧縮版

Page 62

Page 63

まとめ

Page 64

PHPはLispじゃない式指向プログラミングは大変

Page 65

エクストリームスポーツを楽しもう

Page 66

ご静聴ありがとうございました

Page 67

あとPHPでもかなり実用的な静的型検査ができるようになってる

Page 68

関連記事

  • PHP式プログラミング入門 (原稿版)
  • PHPの無名関数式とは何か、そしてPHP7.4のアロー関数にそなえよう
  • Functoolsを作った
  • Functoolsで過剰にスマートなPHPを書こう (無名再帰篇)