意識
- 感覚的に学ぶ
- 「頭」で理解するのではなく「体(感覚)」で理解する
- なぜなら、頭よりも感覚が知っていることのほうが多いから
- お箸を使うときの筋肉の動かし方をすべて記述しようとしても難しい
- ではどうやってお箸を使えるようになったかというと、実践の中で感覚として覚えてきた
- 大人より子どものほうが吸収が早いことがあるのは、子どもは実践を通して学んでいくから
- 一個ずつ、ちょっとずつでいい
- 目を閉じて、落ち着いて、自分の思考の中から、ネガティブな部分を見つけて
- ちょっとだけ良いものに変えて、また見つけたらちょっとだけいいものに変えて、ちょっとだけいいものに変えていくと、いつの間にかネガティブな部分がなくなって、晴れやかでクリアになる
- そこにはなにもない
- 感覚としては、そういうものを背中に背負いつつ、そこにフォーカスせずに、大切なことにフォーカスしているイメージ
- そしたら、背中に背負ってたものがどんどん軽くなっていつの間にかどっかいくんだ
考え
- 結局、どんなにすごそうに見える人も、自分と同じ人間であり、泥臭いことをしているんだ、ということ
- 最終結果だけを見ているから、天才だとか才能があるとか考えがちだけど
- 実際には日々の小さな積み重ねがそこに現れている
- その泥臭い小さい積み重ねを、楽しんでやっているのか、苦痛と思ってやっているのかはまた別の話だけど、
- いずれにせよ、そういう小さい積み重ねがあってすごいように見えている
- 人生とは、種をまいて収穫して、種をまいて収穫して…の繰り返しである
- つまり、種をまいて育てる育成期と、それを収穫できる収穫期がある、ということだ
- あることで成功した人は、それまで育ててきた育成期を経て収穫期を迎えた、ということだ
- 収穫期を迎えてそこでおしまいではなく、また種をまき育成期にはいる
- 自分が今どんな種をまいているのか、それが収穫されたらどんな素晴らしい光景がそこにあるのか
- 良い野菜そのものではなく、良い野菜を育てるプロセスそのものに喜びがあるんだ
- 良い野菜がほしいだけなら、高級スーパーに買いに行けばいい
- そのプロセスを楽しむこと
- それを想像してワクワクすること
- 「結果が全てだ」というのは一つのものの見方にすぎない、ということは認識する必要がある
- その背後には、結果を得られれば私は幸せになる――結果を得られなければ幸せなれない、という信念がある
- もしそのように考えていると結果を得るのが難しくなる
- なぜなら、人生において常に結果が得られるわけではないから
- 結果を得られなければ幸せではない、というスタンスでいるとき、プロセスを楽しむことができない
- あるいはプロセスを楽しむ、ということを忘れてしまう
- 人生とはプロセスそのものなに、プロセスをおろそかにしてしまう
- 人生の満足度とは、結果をどれほど得たかではなく、
- 友達とゲームして遊んだ日々
- 仲間とともに切磋琢磨しながら成長してきた達成感
- つまり、老後に自分にとって人生は良いものであったかを問われとき、どれだけお金や富や名声があったとしても、そのプロセスが苦しいものであったなら、良い人生とは思えないのではないか、ということだ
- 多くの人たちは結果でものを判断しようとする
- そこに惑わされないことだ
学び
Railway Oriented Programming
関数型プログラミングのパラダイムはアプリケーション開発に必要なのか?
TypeScriptで始めるRailway Oriented Programming
【Swift】鉄道指向プログラミング(Railway Oriented Programming)でResultの使い方を学ぶ
- Railway Oriented Programming (ROP)
- 関数型でエラーハンドリングをするための一つの手法
- 鉄道のように、ある処理をして成功すれば成功した道、失敗すれば失敗した道を通すような?
- ある関数の出力が次の関数の入力と同じであれば関数は連結することができる
fn1(input: PineApple): Apple
⇒fn2(input: Apple): Banana
- では、ある関数の出力がエラーを含む場合は?
fn1(input: PineApple): Result<Apple, Error>
- もし成功していたら次の関数につなぎ、失敗していたら次の関数は実行せずに失敗の道を通る
Against Railway-Oriented Programming
Result
はドメインモデルのエラーに使うと強力- ドメインモデルのエラーを型として明示できるし適切にハンドリングすることができる
Result
を使うたいだけであれば Effect よりシンプルで良さそうResult
のネストへの対処?
pipe
はなに?- 純粋関数の合成を読みやすい形にできるもの?
Math.abs(plusTen(minusFive(0)))
pipe([minufFive, plusTen, Math.abs], 0)
- 純粋関数の合成を読みやすい形にできるもの?
Building Pipelines | Effect Documentation
- ちょっとまだ難しい
Effect.map
はなに?Effect.Effect
型をResult<Success, Error>
のSuccess
のほうだけ処理するようなもんか
import { Effect, pipe } from "effect"
const addOne = (n: number) => n + 1
pipe(
Effect.succeed(10),
Effect.map(addOne),
Effect.map(console.log) // 11
)
Effect.flatMap
Effect
型のネストをフラットに?Effect<Effect<number, never>, never>
⇒Effect<number, never>
pipe(
Effect.succeed(10),
Effect.map(addOne),
Effect.flatMap(n => Effect.succeed(n)),
Effect.map(console.log) // 11
)
Effect.andThen
Effect.map
との違いは?- 値を返そうが
Promise
を返そうがEffect
を返そうが値をいい感じにとって次に渡してくれるってこと?
- 値を返そうが
pipe(
Effect.succeed(10),
Effect.andThen(addOne),
Effect.andThen(n => Effect.succeed(n)),
Effect.andThen(n => Promise.resolve(n + 10)),
Effect.andThen(console.log) // 21
)
pipe(
Effect.succeed(10),
Effect.andThen(addOne),
Effect.andThen(Promise.resolve(100)),
Effect.andThen(console.log) // 100
)
Effect.promise
Promise
を返す関数をEffect
でラップ- 成功する場合のみ
- エラーを返した場合は defect として扱われる
Effect.tryPromise
- 失敗する可能性がある場合はこっち
- エラーがある場合
UnknownException
として扱う - または
catch
を指定してエラーをリマップできる
// Effect<Response, UnknownException>
Effect.tryPromise(() => fetch('https://...'))
// or
// Effect<Response, Error>
Effect.tryPromise({
try: () => fetch('https://...'),
catch: (unknown) => new Error(`something went wrong ${unknown}`)
})
- defect なに?
- 英語的には 欠陥・欠点・弱点
- ef-fect にたいして de-fect
Effect
的にはUnexpected Exception
かね?
- 英語的には 欠陥・欠点・弱点
Option
とandThen
Option<T>
はEffect<T, NoSuchElementException>
と扱われる
// Effect<number, NoSuchElementException>
pipe(
Effect.succeed(10),
Effect.andThen((n) => n > 5 ? Option.some(n) : Option.none())
)
Effect.tap
- 値を変更することなく、間に副作用をいれることができる
- 途中でログを挟みたいときなど
pipe(
Effect.succeed(10),
Effect.tap(n => console.log(n)), // 10
Effect.andThen((n) => n + 1), // n は引き続き使える
Effect.andThen(console.log), // 11
Effect.andThen(n => n + 1) // Error: console.log の戻り値は void のため計算不可
)
Effect.all
- 複数のエフェクトを一つにまとめて、結果を配列で得る
const fetchDataA = Effect.promise(() =>
Promise.resolve({ foo: 'foo' })
)
const fetchDataB = Effect.propmise(() =>
Promise.resolve({ bar: 'bar'})
)
pipe(
Effect.all([fetchDataA, fetchDataB]),
Effect.andThen(([dataA, dataB]) =>
// do something with dataA and dataB
doSomething(dataA, dataB)
),
)
- だいぶわかってきた
エラーハンドリング
class ValidationError {
readonly _tag = "ValidationError"
}
class HttpError {
readonly _tag = "ValidationError"
}
pipe(
Effect.fail(new ValidationError()),
Effect.fail(new HttpError()),
// 全エラーをキャッチして
Effect.catchAll((error) => Effect.succeed(`Recovered from ${error._tag}`)),
);