Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fantasy Land support #239

Open
gabejohnson opened this issue May 17, 2018 · 3 comments
Open

Add Fantasy Land support #239

gabejohnson opened this issue May 17, 2018 · 3 comments

Comments

@gabejohnson
Copy link

Continuing the conversation from cujojs/most#347

@briancavalier
Copy link
Member

Hey @gabejohnson, thanks for opening this. I've been watching fantasyland/fantasy-land#286 closely. It'd currently be much simpler for @most/core to implement static-land (it mostly already does, but of is named now) than fantasy-land 3.x, since @most/core streams don't share a common prototype (they only share an interface).

Hence my interest in fantasyland/fantasy-land#286. We'll continue keeping an eye on it.

@Frikki
Copy link
Member

Frikki commented Oct 7, 2020

And this fantasyland/fantasy-land#315

@semmel
Copy link
Contributor

semmel commented Feb 12, 2024

I've toyed around with two approaches integrating Fantasyland support. Both are backwards compatible. I guess, I'd favour the separate package approach (A), since it's not invasive.

Benefits of not going for an add-on

  • TypeScript throughout, (i.e. without importing compiled code)
  • just a single compile-to-JS step

Approach A) Provide a FL flavoured API in @most/core-fl by wrapping Stream with class FantasyLandStream <A>

  • provide a FL<A> Stream class which delegates FL method calls to @most/core functions. See discussion and playground code
  • using the wrapper function, export each @most/core function as FL-flavoured API

Strawman PR

// FL-API.ts
import FantasyLandStream from 'FLDelegate'
import { periodic as _periodic, take as _take,  } from '../core/src/index'
import { compose, curry2, curry3 } from '@most/prelude'
export const fantasyLand = <A>(stream: Stream<A>) =>
  new FantasyLandStream(stream);
  
// Number -> FantasyLandStream ()
export const periodic = compose(fantasyLand, _periodic)

interface Tap {
  <A>(f: (a: A) => any, s: Stream<A>): FantasyLandStream<A>
  <A>(f: (a: A) => any): (s: Stream<A>) => FantasyLandStream<A>
}
export const tap: Tap = curry2((x, y) => fantasyLand(_tap(x, y)))
// …
// FLDelegate.ts
export class FantasyLandStream<A> implements Stream<A>, FunctorFantasyLand<A> {
  constructor(private readonly stream: Stream<A>) {}

  run(sink: Sink<A>, scheduler: Scheduler): Disposable {
    return this.stream.run(sink, scheduler)
  }

  ['fantasy-land/map']<B>(fn: (value: A) => B): FantasyLandStream<B> {
    return fantasyLand<B>(map(fn, this.stream))
  }
  //…
}

Approach B) Add FL support to @most/core by replacing Stream<A> with class FL<A> implements Stream<A>

  • move implementation of all FL functions (map, empty,…) into a single source FL.ts (must be a single file to avoid circular dependencies)
  • in function types replace Stream<A> with FL<A>
  • in the Stream<A> implementations
    • replace extends Stream<A> with implements FL<A>
    • in the constructor insert a super() call
// FL.ts
export abstract class FL<A> implements Stream<A> {
  ['fantasy-land/map']<B>(fn: (a: A) => B): FL<B> {
    return Map.create<A, B>(fn, this)
  }
  ['fantasy-land/empty'](): FL<never> {
    return new Empty()
  }
  // …

  _T?: A
  abstract run (sink: Sink<A>, scheduler: Scheduler): Disposable
}

class Map<A, B> extends FL<B> {
//…
// transform.ts
import { FL, Map } from 'FL'

export const map = <A, B>(f: (a: A) => B, stream: Stream<A>): FL<B> =>
  Map.create(f, stream)
// …

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants