fun
fun copied to clipboard
Do Notation - Post 2.0
Regarding Affect.
Was wondering if we're supposed to execute it straight up on receiving
Ctxor would it make sense to be more likeRTEand actually return aTaskthere.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:
aff1has typeAffect<string, never, string>aff2has typeAffect<never, never, string>- In
xif we remove the invoke with "x" we can step through the pipeline - At
A.bindTo("a")we have typeAffect<string, never, { readonly a: string }> - At
A.bind("B", () => aff2)we have typeAffect<never, never, { readonly a: string, readonly b: string }>This is the first problem, indicating a type error inbindfor Affect. - At
A.map(add)we keep the input type ofnever, 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
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 -> Lfor inner types. - Use
ua,vato 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
Implemented in 2.0.0