點燈坊

失くすものさえない今が強くなるチャンスよ

使用 ap 將 Apply 與包進 Apply 的 Function 綁定

Sam Xiao's Avatar 2021-07-04

支援 ap 的 Object 稱為 Apply,若想傳入 Function 改變其內部值,可將 Function 包進 Apply 再透過 ap 傳入。

Version

Sanctuary 3.1.0

Array

import { ap, add } from 'sanctuary'

let data = [1, 2]

ap ([add (1)]) (data) // ?

data 為 Array,add (1) 為包進 Array 的 function,可使用 ap 將 Array 與 [add (1)] 綁定改變 Array。

ap :: Apply f => f (a -> b) -> f a -> f b
將 Apply 與包進 Apply 的 function 綁定並回傳新 Apply

f (a -> b):包進 Apply 的 function

f a:data 為 Apply

f b:回傳新 Apply

Array 亦是 Apply,因此 ap 也適用

ap001

import { ap, add, negate } from 'sanctuary'

let data = [1, 2]

ap ([add (1), negate]) (data) // ?

也可將多個 function 包在 Array 內,若 datam 的 element,傳入有 n 個 function,則 ap 會產生 m x n element 的新 Array。

ap002

Object

import { ap, add, negate } from 'sanctuary'

let data = { x: 1, y: 2 }

ap ({ x: add (1), y: negate }) (data) // ?

data 為 Object,想傳入 add (1)negate 改變 data,可將 add (1)negate 也包進 Object 再傳入 ap,function 只會影響相同 key 的 property。

ap003

Maybe

Just

import { Just, add, ap } from 'sanctuary'

let data = Just (1)

let add_ = Just (add (1))

ap (add_) (data) // ?

data 為 Maybe,add_ 為包進 Maybe 的 function,可使用 ap 將 Maybe 與 add_ 綁定改變 Maybe。

Data 與 function 必須包在相同 typeclass 的 Object 內,因此都必須是 Maybe

ap005

Nothing

import { Just, Nothing, add, ap } from 'sanctuary'

let data = Nothing

let add_ = Just (add (1))

ap (add_) (data) // ?

data 為 Nothing,則傳入 ap 的 function 不會執行。

ap006

Either

import { Right, add, ap } from 'sanctuary'

let data = Right (1)

let add_ = Right (add (1))

ap (add_) (data) // ?

data 為 Either,add_ 為包進 Either 的 function,可使用 ap 將 Either 與 add_ 綁定改變 Either。

Data 與 function 必須包在相同 typeclass 的 Object 內,因此都必須是 Either

ap008

Left

import { Left, Right, map, add, ap } from 'sanctuary'

let data = Left (1)

let add_ = Right (add (1))

ap (add_) (data) // ?

data 為 Left,則傳入 ap 的 function 不會執行。

ap009

Future

Resolved

import { resolve, fork } from 'fluture'
import { create, env } from 'sanctuary'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { log, error } from 'wink-fp'

let { pipe, add, ap } = create ({ checkTypes: true, env: env.concat (flutureEnv) })

let data = resolve (1)

let add_ = resolve (add (1))

pipe ([
  ap (add_),
  fork (error) (log)
]) (data)

data 為 Future,add_ 為包進 Future 的 function,可使用 ap 將 Future 與 add_ 綁定改變 Future。

Data 與 function 必須包在相同 typeclass 的 Object 內,因此都必須是 Future

ap010

Rejected

import { resolve, reject, fork } from 'fluture'
import { create, env } from 'sanctuary'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { log, error } from 'wink-fp'

let { pipe, add, ap } = create ({ checkTypes: true, env: env.concat (flutureEnv) })

let data = reject (1)

let add_ = resolve (add (1))

pipe ([
  ap (add_),
  fork (error) (log)
]) (data) 

data 為 Rejected,則傳入 ap 的 function 不會執行。

ap011

Conclusion

  • 支援 ap 的 Object 稱為 Apply
  • 可發現 Functor f => map (a -> b) -> f aApply f => ap (f (a -> b)) -> f a 是等效的,只是以不同方式處理 function,Apply 要透過 ap 傳入包進 Apply 的 function;而 Functor 則透過 map 直接傳入 function 即可
  • ap 除了能用在 Array 與 Object 外,也能用在 Maybe、Either 與 Future,因為這些也都是 Apply

Reference

Sanctuary, ap