Skip to content

Add Fantasy Land support #239

Open
Open

Description

@gabejohnson

Continuing the conversation from cujojs/most#347

Activity

  1. briancavalier commented on May 18, 2018

    @briancavalier
    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.

  2. Frikki commented on Oct 7, 2020

    @Frikki
    Member
  3. semmel commented on Feb 12, 2024

    @semmel
    Contributor

    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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions