Bifunctor: Sikat Kanan Kiri

Jan 23, 2020 10:02 · 398 words · 2 minute read #purescript #haskell #functor #functionalprogramming

Bifunctor: Sikat Kanan Kiri
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.

PureScript
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.

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

Dengan ini kedua buah value akhirnya bisa ditransformasi.

Contoh lain. Either.

PureScript
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.

PureScript
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.

PureScript
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 (sumber)

Sekian dan terima kangen.

Edit on