From 360c4048a988a8427f08a1966dc8b5c082920392 Mon Sep 17 00:00:00 2001 From: Patrick Roza Date: Mon, 24 May 2021 23:45:50 +0200 Subject: [PATCH] curry trix. --- apps/api/Tasks/Update.ts | 25 ++++++--------- packages/core/ext/Effect.ts | 18 ++++++++++- packages/core/ext/utils/index.ts | 16 ++++++++++ packages/types/Task/Task.ts | 7 +++-- packages/types/Task/audit.ts | 10 ++++-- packages/types/User.ts | 53 ++++++++++++++++++-------------- 6 files changed, 85 insertions(+), 44 deletions(-) diff --git a/apps/api/Tasks/Update.ts b/apps/api/Tasks/Update.ts index d8f8d0f3..0acdb5c7 100644 --- a/apps/api/Tasks/Update.ts +++ b/apps/api/Tasks/Update.ts @@ -1,5 +1,5 @@ -import * as T from "@effect-ts/core/Effect" -import { constant, identity } from "@effect-ts/core/Function" +import { flow, identity } from "@effect-ts/core/Function" +import * as T from "@effect-ts-app/core/ext/Effect" import * as O from "@effect-ts-app/core/ext/Option" import { handle } from "@effect-ts-app/infra/app" import { Tasks } from "@effect-ts-demo/todo-client" @@ -27,7 +27,10 @@ export default handle(Tasks.Update)(({ id, myDay, ..._ }) => // TODO: Context should perhaps know if changed, and should use a transaction yield* $( - T.tuple(whenChanged(Tasks.save_)(nt, task), whenChanged(Users.save)(nu, user)) + T.tuple( + Tasks.save_["|>"](T.ifDiff(nt, task)), + Users.save["|>"](T.ifDiff(nu, user)) + ) ) }) ) @@ -54,20 +57,12 @@ export function updateTask_( O.fold( // TODO: Attachment removed? () => t, - (a) => - t["|>"]( - Task.addAudit( - TaskAudits.TaskFileAdded.fromAttachment(a)({ userId: user.id }) - ) - ) + flow( + TaskAudits.TaskFileAdded.fromAttachment({ userId: user.id }), + Task.addAuditR(t) + ) ) ) } return [t, user] as const } - -function whenChanged(f: (i: I) => T.Effect) { - return (n: I, orig: I) => T.if(() => f(n), constUnit)(n !== orig) -} - -const constUnit = constant(T.unit) diff --git a/packages/core/ext/Effect.ts b/packages/core/ext/Effect.ts index 5879d504..e003d621 100644 --- a/packages/core/ext/Effect.ts +++ b/packages/core/ext/Effect.ts @@ -5,15 +5,17 @@ import { effectAsyncInterrupt, fail, fromEither, + if_, IO, succeed, succeedWith, tap, + unit, } from "@effect-ts/core/Effect" import type * as Ei from "@effect-ts/core/Either" import * as O from "@effect-ts/core/Option" -import { flow, Lazy, pipe } from "./Function" +import { constant, flow, Lazy, pipe } from "./Function" export const encaseEither = (ei: Ei.Either) => fromEither(() => ei) export const chainEither = (ei: (a: A2) => Ei.Either) => @@ -51,4 +53,18 @@ export function tupleCurriedTap(f: (b: B) => (a: A) => Effect succeed(t[0])["|>"](tap(f(t[1]))) } +export function ifDiffR(f: (i: I) => Effect) { + return (n: I, orig: I) => ifDiff_(n, orig, f) +} + +export function ifDiff(n: I, orig: I) { + return (f: (i: I) => Effect) => ifDiff_(n, orig, f) +} + +export function ifDiff_(n: I, orig: I, f: (i: I) => Effect) { + return if_(n !== orig, () => f(n), constUnit) +} + +const constUnit = constant(unit) + export * from "@effect-ts/core/Effect" diff --git a/packages/core/ext/utils/index.ts b/packages/core/ext/utils/index.ts index 0363f25d..bcd72fe3 100644 --- a/packages/core/ext/utils/index.ts +++ b/packages/core/ext/utils/index.ts @@ -70,3 +70,19 @@ export function capitalize(string: T): Capitalize { export function uncapitalize(string: T): Uncapitalize { return (string.charAt(0).toLowerCase() + string.slice(1)) as Uncapitalize } + +export function tupledCurry(f: (b: B) => (a: A) => C) { + return (t: [A, B]) => f(t[1])(t[0]) +} + +export function reverseCurry(f: (b: B) => (a: A) => C) { + return (a: A) => (b: B) => f(b)(a) +} + +export function curry(f: (a: A, b: B) => C) { + return (b: B) => (a: A) => f(a, b) +} + +export function uncurry(f: (b: B) => (a: A) => C) { + return (a: A, b: B) => f(b)(a) +} diff --git a/packages/types/Task/Task.ts b/packages/types/Task/Task.ts index 2e11831e..8f5ae70d 100644 --- a/packages/types/Task/Task.ts +++ b/packages/types/Task/Task.ts @@ -20,6 +20,7 @@ import { reasonableString, withDefault, } from "@effect-ts-app/core/ext/Schema" +import { curry, reverseCurry, uncurry } from "@effect-ts-app/core/ext/utils" import { TaskId, TaskListIdU, UserId } from "../ids" import { TaskAudit, TaskCreated } from "./audit" @@ -107,9 +108,8 @@ export class Task extends Model()({ static addAudit = (audit: TaskAudit) => Task.lens["|>"](Lens.prop("auditLog"))["|>"](Lens.modify(A.snoc(audit))) - static addAudit_ = (t: Task, audit: TaskAudit) => Task.addAudit(audit)(t) - - static update = (_: OptionalEditableTaskProps) => (t: Task) => Task.update_(t, _) + static addAuditR = reverseCurry(Task.addAudit) + static addAudit_ = uncurry(Task.addAudit) static update_ = (t: Task, _: OptionalEditableTaskProps) => { const nt = { @@ -119,4 +119,5 @@ export class Task extends Model()({ } return nt } + static update = curry(Task.update_) } diff --git a/packages/types/Task/audit.ts b/packages/types/Task/audit.ts index 43c7fc79..90357e36 100644 --- a/packages/types/Task/audit.ts +++ b/packages/types/Task/audit.ts @@ -1,3 +1,4 @@ +import { LazyGetter } from "@effect-ts/core/Utils" import { date, defaultProp, @@ -11,6 +12,7 @@ import { union, UUID, } from "@effect-ts-app/core/ext/Schema" +import { reverseCurry } from "@effect-ts-app/core/ext/utils" import { UserId } from "../ids" import { Attachment, FileName } from "./shared" @@ -34,8 +36,12 @@ export class TaskFileAdded extends Model()({ ...AuditProps("TaskFileAdded"), fileName: prop(FileName), }) { - static fromAttachment(a: Attachment) { - return partialConstructor_(TaskFileAdded, { fileName: a.fileName }) + static fromAttachmentR = (a: Attachment) => + partialConstructor_(TaskFileAdded, { fileName: a.fileName }) + + @LazyGetter() + static get fromAttachment() { + return reverseCurry(TaskFileAdded.fromAttachmentR) } } diff --git a/packages/types/User.ts b/packages/types/User.ts index a3631549..9ebe8863 100644 --- a/packages/types/User.ts +++ b/packages/types/User.ts @@ -1,12 +1,12 @@ import * as A from "@effect-ts/core/Collections/Immutable/Array" import * as O from "@effect-ts/core/Option" import { Option } from "@effect-ts/core/Option" +import { LazyGetter } from "@effect-ts/core/Utils" import { array, date, defaultProp, Email, - GetPartialConstructor, Model, namedC, ParsedShapeOf, @@ -16,6 +16,7 @@ import { props, reasonableString, } from "@effect-ts-app/core/ext/Schema" +import { reverseCurry, uncurry } from "@effect-ts-app/core/ext/utils" import { TaskId, UserId } from "./ids" import { Task } from "./Task" @@ -37,32 +38,38 @@ export class User extends Model()({ myDay: defaultProp(array(MyDay)), phoneNumber: prop(PhoneNumber), }) { - static createTask__ = - (a: GetPartialConstructor) => (u: User) => - User.createTask_(u, a) + @LazyGetter() + static get createTask() { + return reverseCurry(User.createTaskR) + } - static createTask_ = (u: User, a: GetPartialConstructor) => - User.createTask(u)(a) - static createTask = (u: User) => createPartialTask({ createdBy: u.id }) + @LazyGetter() + static get createTask_() { + return uncurry(User.createTask) + } + static createTaskR = (u: User) => createPartialTask({ createdBy: u.id }) - static createTaskList__ = - (a: GetPartialConstructor) => (u: User) => - User.createTaskList_(u, a) + @LazyGetter() + static get createTaskList() { + return reverseCurry(User.createTaskListR) + } - static createTaskList_ = ( - u: User, - a: GetPartialConstructor - ) => User.createTaskList(u)(a) - static createTaskList = (u: User) => createPartialTaskList({ ownerId: u.id }) + @LazyGetter() + static get createTaskList_() { + return uncurry(User.createTaskList) + } + static createTaskListR = (u: User) => createPartialTaskList({ ownerId: u.id }) - static createTaskListGroup__ = - (a: GetPartialConstructor) => (u: User) => - User.createTaskListGroup_(u, a) - static createTaskListGroup_ = ( - u: User, - a: GetPartialConstructor - ) => User.createTaskListGroup(u)(a) - static createTaskListGroup = (u: User) => + @LazyGetter() + static get createTaskListGroup() { + return reverseCurry(User.createTaskListGroupR) + } + + @LazyGetter() + static get createTaskListGroup_() { + return uncurry(User.createTaskListGroup) + } + static createTaskListGroupR = (u: User) => createPartialTaskListGroup({ ownerId: u.id }) static getMyDay = (t: Task) => (u: User) =>