Skip to content
This repository has been archived by the owner on Jan 5, 2023. It is now read-only.

Commit

Permalink
Curry trix.
Browse files Browse the repository at this point in the history
patroza committed May 24, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 03c7f90 commit 62b9246
Showing 7 changed files with 87 additions and 46 deletions.
25 changes: 10 additions & 15 deletions apps/api/Tasks/Update.ts
Original file line number Diff line number Diff line change
@@ -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<I, R, E, A>(f: (i: I) => T.Effect<R, E, A>) {
return (n: I, orig: I) => T.if(() => f(n), constUnit)(n !== orig)
}

const constUnit = constant(T.unit)
4 changes: 2 additions & 2 deletions apps/api/_services/TodoContext.testdata.ts
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ import {

function makeUserTaskCreator(u: User) {
return flow(
User.createTask(u),
User.createTaskR(u),
Task.lens["|>"](Lens.prop("title"))["|>"](
Lens.modify((t) => reasonableStringUnsafe(`${u.name} - ${t}`))
)
@@ -48,7 +48,7 @@ export function makeTestDataUnsafe() {

const users = [patrick, mike, markus]

const createPatrickList = User.createTaskList(patrick)
const createPatrickList = User.createTaskListR(patrick)
const patrickList = createPatrickList({
title: reasonableStringUnsafe("Some Patrick List"),
})
18 changes: 17 additions & 1 deletion packages/core/ext/Effect.ts
Original file line number Diff line number Diff line change
@@ -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 = <E, A>(ei: Ei.Either<E, A>) => fromEither(() => ei)
export const chainEither = <E, A, A2>(ei: (a: A2) => Ei.Either<E, A>) =>
@@ -51,4 +53,18 @@ export function tupleCurriedTap<A, B, R, E, C>(f: (b: B) => (a: A) => Effect<R,
return (t: readonly [A, B]) => succeed(t[0])["|>"](tap(f(t[1])))
}

export function ifDiffR<I, R, E, A>(f: (i: I) => Effect<R, E, A>) {
return (n: I, orig: I) => ifDiff_(n, orig, f)
}

export function ifDiff<I, R, E, A>(n: I, orig: I) {
return (f: (i: I) => Effect<R, E, A>) => ifDiff_(n, orig, f)
}

export function ifDiff_<I, R, E, A>(n: I, orig: I, f: (i: I) => Effect<R, E, A>) {
return if_(n !== orig, () => f(n), constUnit)
}

const constUnit = constant(unit)

export * from "@effect-ts/core/Effect"
16 changes: 16 additions & 0 deletions packages/core/ext/utils/index.ts
Original file line number Diff line number Diff line change
@@ -70,3 +70,19 @@ export function capitalize<T extends string>(string: T): Capitalize<T> {
export function uncapitalize<T extends string>(string: T): Uncapitalize<T> {
return (string.charAt(0).toLowerCase() + string.slice(1)) as Uncapitalize<T>
}

export function tupledCurry<A, B, C>(f: (b: B) => (a: A) => C) {
return (t: [A, B]) => f(t[1])(t[0])
}

export function reverseCurry<A, B, C>(f: (b: B) => (a: A) => C) {
return (a: A) => (b: B) => f(b)(a)
}

export function curry<A, B, C>(f: (a: A, b: B) => C) {
return (b: B) => (a: A) => f(a, b)
}

export function uncurry<A, B, C>(f: (b: B) => (a: A) => C) {
return (a: A, b: B) => f(b)(a)
}
7 changes: 4 additions & 3 deletions packages/types/Task/Task.ts
Original file line number Diff line number Diff line change
@@ -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<Task>()({

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<Task>()({
}
return nt
}
static update = curry(Task.update_)
}
10 changes: 8 additions & 2 deletions packages/types/Task/audit.ts
Original file line number Diff line number Diff line change
@@ -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<TaskFileAdded>()({
...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)
}
}

53 changes: 30 additions & 23 deletions packages/types/User.ts
Original file line number Diff line number Diff line change
@@ -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<User>()({
myDay: defaultProp(array(MyDay)),
phoneNumber: prop(PhoneNumber),
}) {
static createTask__ =
(a: GetPartialConstructor<typeof User["createTask_"]>) => (u: User) =>
User.createTask_(u, a)
@LazyGetter()
static get createTask() {
return reverseCurry(User.createTaskR)
}

static createTask_ = (u: User, a: GetPartialConstructor<typeof User["createTask"]>) =>
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<typeof User["createTaskList_"]>) => (u: User) =>
User.createTaskList_(u, a)
@LazyGetter()
static get createTaskList() {
return reverseCurry(User.createTaskListR)
}

static createTaskList_ = (
u: User,
a: GetPartialConstructor<typeof User["createTaskList"]>
) => 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<typeof User["createTaskListGroup_"]>) => (u: User) =>
User.createTaskListGroup_(u, a)
static createTaskListGroup_ = (
u: User,
a: GetPartialConstructor<typeof User["createTaskListGroup"]>
) => 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) =>

1 comment on commit 62b9246

@vercel
Copy link

@vercel vercel bot commented on 62b9246 May 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.