fun icon indicating copy to clipboard operation
fun copied to clipboard

Do Notation - Post 2.0

Open pixeleet opened this issue 3 years ago • 1 comments
trafficstars

Regarding Affect.

Was wondering if we're supposed to execute it straight up on receiving Ctx or would it make sense to be more like RTE and actually return a Task there.

I know you went for this implementation originally because you dislike the Reader<Task<Either>> ending up in a thunk that still needs to be executed, but on the other side it's quite handy that the computation stays lazy.

Also am wondering what's wrong with the following snippet (that imho should work)

import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
import * as A from "./affect.ts";
import { identity, pipe } from "./fns.ts";

const aff1 = pipe(A.ask<string>(), A.map((a) => a.toUpperCase()));
const aff2 = A.of<string>("b");
const add = ({ a, b }: { a: string; b: string }) => a + b;

const x = pipe(
  aff1,
  A.bindTo("a"),
  A.bind("b", () => aff2),
  A.map(add),
  A.fold((_) => "aa", identity),
)("a");

const y = pipe(
  A.Do(),
  A.bind("a", () => aff1),
  A.bind("b", () => aff2),
  A.map(add),
  A.fold((_) => "aa", identity),
)("a");

assertEquals(await x, "Ab");
assertEquals(await y, "Ab");

Only after resorting to use any a second type parameter this starts to work correctly.

import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
import * as A from "./affect.ts";
import { identity, pipe } from "./fns.ts";

const aff1 = pipe(A.ask<string, any>(), A.map((a) => a.toUpperCase()));
const aff2 = A.of<string, any, string>("b");
const add = ({ a, b }: { a: string; b: string }) => a + b;

const x = pipe(
  aff1,
  A.bindTo("a"),
  A.bind("b", () => aff2),
  A.map(add),
  A.fold((_) => "aa", identity),
)("a");

const y = pipe(
  A.Do(),
  A.bind("a", () => aff1),
  A.bind("b", () => aff2),
  A.map(add),
  A.fold((_) => "aa", identity),
)("a");

assertEquals(await x, "Ab");
assertEquals(await y, "Ab");

What am I doing wrong?

Well, I never really tried using Do notation for Affect, this is likely the first problem. I don't have much time right now, but for the x example I see the following hints from the first code block:

  1. aff1 has type Affect<string, never, string>
  2. aff2 has type Affect<never, never, string>
  3. In x if we remove the invoke with "x" we can step through the pipeline
  4. At A.bindTo("a") we have type Affect<string, never, { readonly a: string }>
  5. At A.bind("B", () => aff2) we have type Affect<never, never, { readonly a: string, readonly b: string }> This is the first problem, indicating a type error in bind for Affect.
  6. At A.map(add) we keep the input type of never, which tracks.

Looks like the type for createDo in derivations.ts is missing initialization to never for typeclasses of length 2, 3, and 4. If you wouldn't mind making a bug ticket referencing these two comments that'd be super helpful!

Originally posted by @baetheus in https://github.com/nullpub/fun/issues/50#issuecomment-1083796171

pixeleet avatar Apr 01 '22 21:04 pixeleet

Do notation Implementation for monad.ts?

  • [ ] Add file block comment at top of file describing the adt/structure.
  • [ ] Check for any missing combinators/derivations that could be implemented.
  • [ ] Modify all combinator variable names to be readable (use style guide).
  • [ ] Add documentation to every export (and // comment local tools).
  • [ ] Check that every function and line is covered by tests in the testing directory.

Style Guide

  • Use A -> I, B -> J, C -> K, D -> L for inner types.
  • Use ua, va to match URI, VRI, etc in generic positions.
  • Implement algebraic structure types (type classes) out to length 4.
  • Use functions over const arrow functions for root exports.
  • Document all type exports.
  • Order file exports by group and then alphabetically. Groups are Types, Constructors, Combinators, Type Class Instances, Type Class Constructors, and Derived Combinators.

Documentation Guide

  • Start with at least one full sentence describing the use case for the export.
  • Include a @since tag (default to 2.0.0)
  • Include an @example tag with a simple example
    • Imports should be relative for functional stuff and otherwise full urls with versions
    • Example should end with at least one assert from the deno std lib

baetheus avatar Oct 01 '22 17:10 baetheus

Implemented in 2.0.0

baetheus avatar Oct 11 '23 19:10 baetheus