Bifunctor: Sikat Kanan Kiri

  •  2 min read
Image by <a href="https://pixabay.com/users/skeeze-272447/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2242958">skeeze</a> from <a href="https://pixabay.com/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2242958">Pixabay</a>
Image by skeeze from Pixabay

Functor adalah sebuah struktur data yang membungkus value lain, yang strukturnya terjaga (preserved) saat transformasi (map). Functor hanya dapat membungkus satu value saja, dan hanya satu value ini saja yang dapat diubah ke bentuk lain.

data Tuple a b = Tuple a b
instance functorTuple :: Functor (Tuple a) where
map fn (Tuple a b) = Tuple a (fn b) -- `a` is unchanged
λ> map (_ + 1) (Tuple 5 8)
Tuple 5 9

Di contoh ini Tuple adalah struktur data yang memiliki dua buah value, a dan b. Namun karena sifat Functor yang hanya bisa mentransformasi satu value saja, kita harus korbankan a dan kasih jalan ke b.

Lalu bagaimana jika kita ingin mentransformasi kedua value Tuple?

Pake BIFUNCTOR bro!!

Sante pak.


Oke, alih-alih menerima satu function transformasi saja seperti Functor, Bifunctor menerima dua buah function transformasi sekaligus: yang satu untuk mengubah nilai a dan yang satunya lagi untuk mengubah nilai b.

bimap (_ - 1) (_ + 1) (Tuple 5 8) -- Tuple 4 9

Dengan ini kedua buah value akhirnya bisa ditransformasi.

Contoh lain. Either.

data Either a b = Left a | Right b
bimap toUpper (_ + 1) (Left "error!") -- Left "ERROR!"
bimap toUpper (_ + 1) (Right 8) -- Right 9

Pola ini sangat mudah dicerna sehingga bisa kita buatkan typeclass-nya sendiri, yang akan kita namakan Bifunctor, yang memiliki method bernama bimap, yang mengambil dua buah function, yang tetap preserve struktur data tersebut, yang yaang bikinin teh dong.

class Bifunctor f where
bimap :: forall a b c d. (a -> b) -> (c -> d) -> f a c -> f b d

Karena bimap adalah method dari sebuah typeclass, seseorang gak bisa begitu saja menggunakan method ini. Struktur data yang dimanipulasi harus terlebih dahulu memiliki instance Bifunctor.

instance bifunctorTuple :: Bifunctor Tuple where
bimap f g (Tuple x y) = Tuple (f x) (g y)
instance bifunctorEither :: Bifunctor Either where
bimap f _ (Left l) = Left (f l)
bimap _ g (Right r) = Right (g r)

Semua struktur data yang memiliki dua buah type paramater dapat dijadikan Bifunctor selama kedua type parameter-nya covariant. Maaf, ini kalimat sebenarnya kopas aja dari sini. Bisa di-skip karena gak peting. Tapi kalau penasaran, saya include gist dari apa yang dimaksud dengan Covariant dan Contravariant 👇🏻

Rumus Covariant & Contravariant
Rumus Covariant & Contravariant

Check this

Sekian dan terima kangen.