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を書こう (無名再帰篇)