Transcript

Applicative Functors in Swift

@kazu0620

自己紹介

坂本 和大( @kazu0620 ) Sansan株式会社 Eight事業部所属

過去に個人で開発したアプリ - 秘密のアルバム(40万DL!) - にゃんこ(15万DL!)

はじめに

Swift その2 Advent Calendar 2015

• 「Optionalな文字列同士を良い感じに結合する」という記事を書いた

http://qiita.com/kazu0620/items/f2a6272c6b8b7bcbaa42

• アプリカティブスタイルについてのコメントを@koher さんから頂いた!

curry(+) <^> a <*> b

RunesとCurryというライブラリを利用すると上記の様な表現が出来るとのこと!

便利そうだが…

• <*>とは?

• curryって関数は何してるのか?

• <^>って何だろ?

• 具体的に何がどう嬉しいのか?

ので、調べてみた

本日のゴール

が何をしてるのか理解して、Runesでアプリカティブスタイルを使えるようになる!

curry(+) <^> a <*> b

箱の話をしよう

「文脈と値を持った箱」というものがあるらしい• Optionalは箱(よく聞くやつ)

• ArrayもOptionalと同じく箱(たまに聞くやつ)

• つまり...?

reference: Functors, Applicatives, And Monads In Pictures(最高の資料)

http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html

• 2(a)という「値」と、計算が失敗したかもしれない(nilかもしれない)という「文脈」を持っている。

reference: Functors, Applicatives, And Monads In Pictureshttp://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html

• 箱に入った値に対して、関数を適用するには?

• 箱から開けないと(unwrap)、関数を適用できない

箱を開けずに関数を適用するには?

朗報

「箱」たちは、基本的にすべて箱を開けずに値を操作するための関数を持っている!

map

• mapは、箱を開けることなく値を操作するためのメソッド

• さっきから「箱」と呼んでるものはこのmapというメソッドを備えている

http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.htmlreference: Functors, Applicatives, And Monads In Pictures

Fanctorとは?

Fanctor

• 実はすでにFanctorについては説明済み

• さっきから言ってる「箱」 = Fanctor

• Fanctorは、文脈(nilかもしれない…など)を持った値

• mapを使うと文脈を保ったまま関数を値に適用できる

• 厳密には、Fanctor則と呼ばれるルールを満たす型のこと

• mapを利用して、箱を開けることなく中の値を操作できる。配列も同じ。

http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.htmlreference: Functors, Applicatives, And Monads In Pictures

Applicative Functorとは?

Applicative Functor

• Fanctorのすごいやつ

• Swiftの場合は、言語仕様にはない。が、Runesというライブラリを利用すれば実現できる。

• 何ができるのか…?

<*>

<*>とApplicative Functor

• Fanctorがmapを備えていたように、Applicative Functorは<*>を備えている

• <*>は「箱に包まれた関数」と「箱に包まれた値」を引数にとる

<*>とApplicative Functor

• 「箱に包まれた値」

• 「箱に包まれた関数?」

Optional(箱)の中にはクロージャだって格納できる

<*>とApplicative Functor

に、箱を開けずに適用するには?

<*>とApplicative FunctorflatMap+mapでもできなくはないが…

<*>を使った方がシンプル&わかりやすい!

<*>は を に適用している

<*>とApplicative Functor

http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.htmlreference: Functors, Applicatives, And Monads In Pictures

Applicative Functorは、箱の中の関数を、箱の中の値に適用してくれる!

引数が複数ある関数複数のOptional値に対して関数を適用したいとき<*>は便利!

sumThreeElementsというOptionalではない値を引数にとる関数をx, y, z(Optional) に適用できてる!

・そして、さりげなく現れた「curry」

引数が複数ある関数curryは、Curryというライブラリのメソッド。これを呼び出さないと、

になる。<*>は「箱に包まれた関数」と「箱に包まれた値」を引数にとる。

「箱に包まれた値」<*>「箱に包まれた値」

引数が複数ある関数

これの返り値が関数であってほしい…

引数:x

返り値:yを引数とする関数(その返り値はzを引数とする関数)にsumTreeElementsを変換することさえ出来れば…

カリー化(高階関数)

• 高階関数: 引数として関数をとったり返り値として関数を返す関数

• カリー化: 複数の引数をとる関数を、1つの引数を取り、残りの引数をとる関数に定義を書き換えること(多分)

引数が複数ある関数というわけで、Curryを利用してカリー化することで、複数の引数がある関数も適用できるように!

返り値は「箱に包まれた関数」

返り値は「箱に包まれた関数」

pure

• +もカリー化して、<*>で繋げて書くことが出来る

• pureは、.Someと同じ。「文脈を持った箱」のデフォルト値で包む。

• じゃ、.Someで良いじゃん?

pure

• xやyがOptional型とは限らない

• アプリカティブスタイルは、アプリカティブ則を満たす型なら何にでも適応できる

• pureを使っておけば中の値がArrayでも安心

同じ

さらに

• result1とresult2は同じ結果になる

• このa.map(f)の記述は頻出なのでショートカットが用意されている

• <^> !

<^>

• 上記の3つは、同じ処理

• <^> を使うことで、(+)をxとyに適用するんだぞ、ということがわかりやすくなる

というわけで

curry(+) <^> a <*> b

• +という関数をカリー化し

• Optionalのデフォルト値(.Some)でその関数を包み

• <*>を使い、Optionalに包まれたaとbに、unrwap

することなく+を適用している

※わかりやすさのためにOptionalと書いたが、アプリカティブ則を満たす型ならなんでも良い

で、結局何が便利なの?

アプリカティブスタイルのメリット

• Optionalでない値を取る関数も、UnwrapせずにOptionalに適用できる

• 複数のOptionalをUnwrapすることなく計算できる

• プロダクトで使ってみて、他良いとこあったら共有します!

Functor, Applicative, そしてMonadについてもっと知りたい方は…

We're hiring!

• Sansan株式会社では、Swiftを書くのが好きなエンジニアを絶賛募集中

• Kotlin好きなandoridエンジニアも絶賛募集中

• React.jsをゴリゴリ書きたいフロントエンジニアも

• ruby/C#なエンジニアも!

We're hiring!

• 興味あれば、 wantedlyか会社の採用ページから応募を!

• https://www.wantedly.com/companies/Sansan/projects

• http://jp.corp-sansan.com/recruit/job/index.html

• (@kazu0620にコッソリ連絡くれる、でもOK)

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


Top Related