// 01. capability 파라미터와 effects 절 // // 어순: fn 이름(파라미터) effects {...} -> 반환타입 // 파라미터는 기본이 빌림(use)이다. 소유를 가져갈 때만 own을 붙인다. import "cool.dev/std/list" as List pub fn refund_order( pay: PaymentGateway, id: OrderId, ) effects {PaymentGateway.refund} -> Result[Receipt, PayError] { pay.refund(id) } // capability 둘, effect 둘. pub fn refund_and_log( pay: PaymentGateway, log: Logger, id: OrderId, ) effects {PaymentGateway.refund, Logger.write} -> Result[Receipt, PayError] { let receipt = pay.refund(id)? log.write("refunded: ", id) Ok(receipt) } // capability 셋 이상은 struct로 접는다 (표준 관용구). // Deps는 affine 필드를 가지므로 전이적으로 affine이고, 무표기이므로 빌려 쓴다. pub struct Deps { pay: PaymentGateway, log: Logger, db: Database, } pub fn checkout( deps: Deps, order: Order, ) effects {PaymentGateway.charge, Database.write, Logger.write} -> Result[Receipt, Error] { let receipt = deps.pay.charge(order.id, order.amount)? deps.db.write(receipt)? deps.log.write("checkout: ", order.id) Ok(receipt) } // 빌린 값을 다른 빌림 자리로 넘기는 것은 허용된다 (복제가 아니다). // // each가 아니라 map인 이유: 결과를 버릴 방법이 언어에 없다. each는 값을 // 남기지 않는 클로저만 받으므로 Result를 삼킬 수 없고, ?는 클로저 밖으로 // 나가지 못한다. 실패를 못 본 척하려면 명시적으로 match해야 한다. pub fn refund_all( pay: PaymentGateway, ids: List[OrderId], ) effects {PaymentGateway.refund} -> List[Result[Receipt, PayError]] { List.map(ids, fn(id) { refund_order(pay, id) }) }