Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Pythonで鉄道指向プログラミング
Search
USABARASHI
July 20, 2022
Programming
1.6k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Pythonで鉄道指向プログラミング
USABARASHI
July 20, 2022
More Decks by USABARASHI
See All by USABARASHI
Nix入門 devShell
usabarashi
2
780
Other Decks in Programming
See All in Programming
[Dev Group Paris Octobre 26] Agentforce, SIforce, Claudeforce, Slackbot… on s'y retrouve ?
nabondance
0
110
sbt 2.0: takeoff
eed3si9n
0
160
AWSに止められる覚悟してますか?
morizo_1984
2
540
AWS CDKのカスタムリソースでContinuum(旧Security Agent)を実装した話 | Implementing Continuum (formerly Security Agent) via AWS CDK Custom Resource
akihisaikeda
2
150
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
300
Jetpack Compose Mechanisms
skydoves
3
820
最近”作らせてる” ローカルAIアプリの話
akit37
0
480
AIに “答え“を書かせるのを やめてみた
___akari11
0
120
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.9k
ジョジョの世界をXRで再現する
mofurune
0
170
Rでドレミ/Do-Re-Mi_with_R
florets1
0
130
Railsのためのパスキー実践入門 〜マルチテナントSaaSでの意思決定〜
utakaha
3
670
Featured
See All Featured
Visualization
eitanlees
153
17k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.4k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Designing for Performance
lara
612
70k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Producing Creativity
orderedlist
PRO
348
41k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
580
Exploring anti-patterns in Rails
aemeredith
4
540
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
570
GitHub's CSS Performance
jonrohan
1033
470k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
800
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
360
Transcript
Pythonで 鉄道指向プログラミング Haskell, Scala, F#, Rust, … etc のアレ Python
3.10, Pylance v2022.6.30 2022/07/20 @usabarashi 1
どんな人?こんな人 Python歴 • 〜2019/09: Elm, Scala, TSを書いていた • 2019/10: Pythonを触り始める
• 2022/06: 未だに「Pythonicって何やねん...」という日々 2
鉄道指向 プログラミング 3
失敗/成功の判断を掛け合わせる • Railway Oriented Programing • Domain Modeling Made Functional
- Chaining Result-Generating Functional • レールに乗らない失敗 /成功はType Errorになる • 失敗したら成功のレールには戻らな い • いつ失敗しても失敗のレールに乗る • 最後まで成功すると成功になる • 失敗の種類が決まっている 4
Haskell: do notation 5
Scala: For Comprehension 6
F#: Computation Expression 7
Rust: Question mark operator 8
Pythonで再現してみる 9
Python仕様 • from typing import Callable, Generic, TypeAlias, TypeVar ◦
T = TypeVar(“T”) ◦ class List(Generic[T]): ▪ Tは型が束縛される変数なので型変数 ▪ List[T]はT型を処理するList型 ▪ List[int]はint型を処理するList型 ▪ Callable[[A, B], C]はA型, B型を引数にとりC型を返却する関数 • from collections.abc import Generator ◦ variable = yield process() ◦ StopIteration.value ▪ Generator[Y, S, R] <: Iterator <: Iterable ▪ Y: yieldの右側のprocessの結果の型変数 ▪ S: = yieldの左側のvariableに束縛する値の型変数 ▪ R: StopIteration.valueの型変数 10
失敗/成功の型を定義する 失敗/成功の定義 class Either(Generic[L, R]): Either[L, R] 失敗の定義 class Left(Either[L,
R): Left[L, R] 成功の定義 class Right(Either[L, R]): Right[L, R] 11
失敗/成功の型を定義する 失敗/成功のどちらかを返す def either(...) -> Either[L, R]: if …: return
Left[L, R](...) else: return Right[L, R](...) 12
シグネチャに失敗の値の型を定義する 失敗したらLeft[str, Any]を返す return Left[str, Any] 成功したらRight[str, Any]を返す return Right[str,
Any] ※ TypeAliasから型変数を指定できる EitherDo: TypeAlias = Generator[Either[L, Any], None, R] 13
EitherDo: TypeAlias = Generator[Either[L, Any], None, R] 上から下へ, 右から左への二次元と考える と理解しやすい
↓ =yield from Left[L, Any] ↓ Any=yield from Right[L, Any] return R StopIteration.value 一連の処理をGenerator関数で定義する 14
失敗を早期リターンする ↓ =yield from Left[L, Any] サブジェネレーターからLeft[L, Any]を貰う class Either(Generic[L,
R]): @abstractmethod def __iter__(self) -> Generator[Either[L, R], None, R]: 失敗ならLeft[L, Any]をそのままリターンする @staticmethod def do(...) -> Callable[P, Either[L, R]] … except ShortCircuit as short_circuit: return cast(Monad[A], short_circuit.state) …. ※ 失敗パターンはシグネチャに明記され ている 15
途中の処理結果を束縛する ↓ Any=yield from Right[L, Any] サブジェネレーターからRight[L, Any]を貰う class Either(Generic[L,
R]): @abstractmethod def __iter__(self) -> Generator[Either[L, R], None, R]: 成功ならサブジェネレーターのRをsendする @staticmethod def do(...) -> Callable[P, Either[L, R]] … case _ if type(yield_) is type(composite): composite = composite.flat_map(lambda _: cast(Monad[Any], yield_)) ※ サブジェネレーターの R: StopIteration.valueで暗黙的に束縛される 16
成功をリターンする return R StopIteration.value yieldがなくなったらreturnに相当する StopIteration.valueをリターンする @staticmethod def do(...) ->
Callable[P, Either[L, R]] … return cast(Monad[A], composite.map(lambda _: result)) ※ 成功のRight[L, R]型へあわせる 17
失敗/成功のどちらかだけ である可能性を定義する SubType: TypeAlias = Left[L, R] | Right[L, R]
@property def pattern(self) -> SubType[L, R]: return self ※ どこから継承されるか分からないので 可能性を具体的に制限する ※ 動的なメソッドだとtype narrowingが固 定されないのでpropertyで静的な値として 定義する pattern() pattern 18
失敗/成功を判定する class Left(Either[L, R]): __match_args__ = ("value",) self.value class Right(Either[L,
R]): __match_args__ = ("value",) self.value ※ パターンを網羅できていない場合は警 告が表示される 19
同じ構文で記述する: nullかも知れない • if var is None: • if var
is not None: • if isinstance(var, None): とか書かない ※ if Xxxx is type(var)は type narrowingされない 20
同じ構文で記述する: 例外が発生するかも知れない try: … except ExceptionA as exception_a: … raise
ExceptionB from exception_a except Exception: … raise else: … とか書かない ※ どこからどのようなExceptionがraiseされているか 静的解析できない 例外とは何か例外的なもの(ある意味、あきらめ)を表現するものであるとした場合、失敗は想定できる結 果であるため、その失敗を例外としてモデリングすることは意味的におかしいことになってしまいます。 セキュア・バイ・デザイン - 安全性を考えた処理失敗時の対策 21
文でなく式にする 文: 処理 式: 結果 = 処理 def method(self: A,
function: Callable[[A], B]) -> B: … result = sample_a .method(lambda self: SampleB(self.value)) def fold( self, left: Callable[[L], U], right: Callable[[R], U] ) -> U: … json_result = either.fold( left=lambda error: Json変換処理(error), right=lambda result: Json変換処理(result) ) 22
で, 実務で使えるの? 23
ビジネスロジック型パズル 24
ビジネスロジック型パズル 25
ビジネスロジック型パズル 26
ビジネスロジック型パズル 27
エンタープライズの鉄道 • 申請 ◦ 決裁 ◦ 未承認, 却下 • 機密
◦ 参照権限あり ◦ 参照権限なし 28
参考文献 • PyPI: pycategory • Railway Oriented Programing • Domain
Modeling Made Functional • 明日から使える実践エラーハンドリング • セキュア・バイ・デザイン • 圏論とモナドシリーズ • Scala, Scalaz, Cats 29