Code Monkey home page Code Monkey logo

prelude-ts's Introduction

prelude-ts

NPM version Tests apidoc

Intro

prelude-ts (previously prelude.ts) is a TypeScript library which aims to make functional programming concepts accessible and productive in TypeScript. Note that even though it's written in TypeScript, it's perfectly usable from JavaScript (including ES5)!

It provides persistent immutable collections (Vector, Set, Map, Stream), and constructs such as Option, Either, Predicate and Future.

Vector.of(1,2,3)
  .map(x => x*2)
  .head()
// => Option.of(2)

Option.sequence(
  Vector.of(Option.of(1), Option.of(2)))
// => Option.of(Vector.of(1,2))

Vector.of(1,2,3,4).groupBy(x => x%2)
// => HashMap.of([0, Vector.of(2,4)],[1, Vector.of(1,3)])

Vector.of(1,2,3).zip("a", "b", "c").takeWhile(([k,v]) => k<3)
// Vector.of([1,"a"],[2,"b"])

HashMap.of(["a",1],["b",2]).get("a")
// Option.of(1)

The collections are also JavaScript iterables, so if you have an ES6 runtime, you can use the for .. of construct on them. If you're not familiar with immutable collections, list.append(newItem) keeps list unchanged; append() returns a new list. Immutability helps reasoning about code.

You can check the User Guide, and browse the API documentation, or our blog. Note that the constructors are private, and you should use static methods to build items — for instance: Option.of, Vector.of, Vector.ofIterable, and so on.

HashSet and HashMap are implemented using the HAMT algorithm, and concretely the hamt_plus library. Vector is implemented through a bit-mapped vector trie and concretely the list library, as of 0.7.7. In addition, the library is written in idiomatic JavaScript style, with loops instead of recursion, so the performance should be good (see benchmarks here comparing to immutable.js and more). list and hamt_plus are the two only dependencies of prelude-ts.

Set, Map and equality

JavaScript doesn't have structural equality, except for primitive types. So 1 === 1 is true, but [1] === [1] is not, and neither is {a:1} === {a:1}. This poses problems for collections, because if you have a Set, you don't want duplicate elements because of this limited definition of equality.

For that reason, prelude-ts encourages you to define for your non-primitive types methods equals(other: any): boolean and hashCode(): number (the same methods that immutable.js uses). With these methods, structural equality is achievable, and indeed Vector.of(1,2,3).equals(Vector.of(1,2,3)) is true. However this can only work if the values you put in collections have themselves properly defined equality (see how prelude-ts can help). If these values don't have structural equality, then we can get no better than === behavior.

prelude-ts attempts to assist the programmer with this; it tries to encourage the developer to do the right thing. It'll refuse types without obviously properly defined equality in Sets and in Maps keys, so HashSet.of([1]), or Vector.of([1]).equals(Vector.of([2])) will not compile. For both of these, you get (a longer version of) this message:

Type 'number[]' is not assignable to type 'HasEquals'.
  Property 'equals' is missing in type 'number[]'.

See the User Guide for more details.

Installation

TypeScript must know about Iterable, an ES6 feature (but present in most browsers) to compile prelude-ts. If you use TypeScript and target ES5, a minimum change to your tsconfig.json could be to add:

"lib": ["DOM", "ES5", "ScriptHost", "es2015.iterable"]

(compared to the default ES5 settings it only adds 'es2015.iterable')

Using in Node.js

Just add the dependency in your package.json and start using it (like import { Vector } from "prelude-ts";, or const { Vector } = require("prelude-ts"); if you use commonjs). Everything should work, including type-checking if you use TypeScript. prelude-ts also provides pretty-printing in the node REPL.

Using in the browser

Add the dependency in your package.json; TypeScript should automatically register the type definitions.

The npm package contains the files dist/src/prelude_ts.js and dist/src/prelude_ts.min.js, which are UMD bundles; they work with other module systems and set prelude_ts as a window global if no module system is found. Include the relevant one in your index.html in script tags:

<script src="node_modules/prelude-ts/dist/src/prelude_ts.min.js"></script>

You shouldn't have an issue to import prelude-ts in your application, but if you use modules it gets a little more complicated. One solution if you use them is to create an imports.d.ts file with the following contents:

// https://github.com/Microsoft/TypeScript/issues/3180#issuecomment-283007750
import * as _P from 'prelude-ts';
export as namespace prelude_ts;
export = _P;

Then in a .ts file of your application, outside of a module, you can do:

import Vector = prelude_ts.Vector;

- to get values without the namespace.

Finally, if you also include dist/src/chrome_dev_tools_formatters.js through a script tag, and enable Chrome custom formatters, then you can get a nice display of prelude-ts values in the Chrome debugger.

Wishlist/upcoming features

  • CharSeq, a string wrapper?
  • Non-empty vector? (already have non-empty linkedlist)
  • Make use of trampolining or a similar technique in Stream to avoid stack overflow exceptions on very large streams
  • More functions on existing classes

Out of scope for prelude-ts

  • Free monads
  • Monad transformers
  • Effect tracking
  • Higher-kinded types simulation

I think these concepts are not expressible in a good enough manner in a language such as TypeScript.

Alternatives and Influences

  • monet.js -- only has the List and Option collections, implemented in functional-style ES5. The implementation, using recursion, means its list type is noticeably slower than prelude-ts's.
  • immutable.js -- doesn't have the Option concept; the types can be clunky.
  • sanctuary offers global functions like S.filter(S.where(...)) while prelude-ts prefers a fluent-API style like list.filter(..).sortBy(...). Also, sanctuary doesn't offer sets and maps. On the other hand, sanctuary has some JS runtime type system support, which prelude-ts doesn't have.
  • ramdajs offers global functions like R.filter(R.where(...)) while prelude-ts prefers a fluent-API style like list.filter(..).sortBy(...). Also, ramda doesn't offer sets and maps. Ramda also uses currying a lot out of the box, which may not be intuitive to a number of developers. In prelude, currying & partial application are opt-in.
  • lodash also has global functions, and many functions mutate the collections.
  • vavr -- it's a Java library, but it's the main inspiration for prelude-ts. Note that vavr is inspired by the Scala library, so prelude-ts also is, transitively.

TypeScript version

As of 0.8.2, prelude requires TypeScript 3.1 or newer.

Commands

npm install

npm test

npm run-script docgen

npm run benchmarks

Related projects

  • Prelude-IO, a library offering IO features -including deserializing and validation- on top of prelude-ts, emphasizing type-safety and immutability

prelude-ts's People

Contributors

aleksei-berezkin avatar annoiiyed avatar antoine-wdg-rmz avatar chocolateboy avatar emmanueltouzery avatar fmw avatar gabebw avatar hraun avatar malcolmredheron avatar wuzzeb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prelude-ts's Issues

feat(): Try monad

Hello,

First, thanks for the work you've done. It's a great lib with many good implementations 👍( message from a VAVR fan !)

But, I would like to know if you plan to integrate some concept like the Try which is very useful for some pattern of code in Javascript. (like this one)

In our case, we want to avoid some kind of code, the most common is the following :

function extract(foo) {
  if (foo && foo.bar && foo.bar.another && foo.bar.another.and && foo.bar.another.and.again) {
    return foo.bar.another.and.again;
  }
  return null;

By doing this kind of thing:

function extract(foo) {
  return Try.of(() => foo.bar.another.and.again).getOrElse(null);

Or even better, simply return the monad and let the caller decide if null is a good candidate (which is not often the case)

So, do you plan to integrate this kind of element? Are you open to PR about this evolution?

/cc @Neonox31 @Yann29

Vector.select(fn: (length: number) => Option<number>): Option<T>

In other words, get item given a function which calculates index given current vector length. This adds some sugar for my particular task: getting random item which is now like

const items = vector.map(...)....;
if (items.isEmpty()) {
    return undefined;
}
return items.get(getRandom(0, items.length)).getOrThrow();

It'll be also useful for getting median and other quantiles.

Perhaps it worth allowing selecting multiple items like Numpy-style, so signature will be like

Vector.select(fn: (length: number) => Vector<number>): Vector<T>

Or create both versions using overload. What are your thoughts?

Can areEqual be undefined-safe too?

As

* if possible, degrades to === if not available, and is also null-safe.
, says, areEqual is null-safe. However, the signature accepts undefined, and then it crashes if the undefined is in obj (versus obj2).

is there a reason that undefined isn't handled here? Or would you take a PR that changes this?

constant

Hi there :)

Is there any chance to get a real, serious constant binding, that does what it says?

So deep freeze combined with casual const.

Thanks a lot

Edit: Seems like readonly does the job.

Future Sequence / MaxConcurrent = 1

Hi,
i'm trying to run some futures after each other, so i thought i could use the traverse function with maxConcurrent property set to one.

In my example, it doesn't work as i expected. The returned result shows me, that all futures are triggered at the same time.

const identity = x => x;

const createFuture = (message, timeout, ok) => 
    Future.ofPromiseCtor((resolve, reject) => {
        console.log("before:", message);

        setTimeout(() => { 
            console.log("after:", message); 
            return ok ? resolve("resolved") : reject("rejected")
        }, timeout);
    });

const futures = [
    createFuture("aaa", 1000, true),
    createFuture("bbb", 500, true),
];

Future.traverse(futures, identity, { maxConcurrent: 1 });

The log:

before: aaa
before: bbb
after: bbb
after: aaa

Two suggestions about Ordering

1)Right now there are

sortOn(getKey: ((v:T)=>number)|((v:T)=>string))
minOn(getNumber: (v:T)=>number)

Maybe It should be something like

type NativeOrderable = number | string | boolean
minOn(getKey: (v:T)=> NativeOrderable)
sortOn(getKey: (v:T) => NativeOrderable)
  1. There is a common scenario when you want to sort something by two properties
type Foo = {a: number, b: number, c: number}

It's possible to use sortBy

fooList.sortBy((x,y) => arrayCompare([x.a, x.b], [y.a, y.b]))

But I think something like this could be better

sortWith<U>(map: T => U, compare: (v1:U,v2:U)=>Ordering)
fooList.sortWith(x => [x.a, x.b], arrayCompare)

or maybe even

sortOn(getKey: (v:T) => NativeOrderable | U, compare?: (v1:U,v2:U)=>Ordering)

HashMap equality calculated incorrectly

The following hashCodes should not be equal, but they are:

expect(HashMap.of(["a", 1], ["b", 0]).hashCode()).not.toBe(HashMap.of(["a", 0], ["b", 1]).hashCode());

The reason for this is that the HashMap hash code is calculated for the pairs in isolation, combining the hash codes of the kv-pairs and summing them up.

Calculating the pairs in isolation is correct because I think the order is not guaranteed in a HashMap (otherwise you could just send the whole list entries to fieldsToHashCode instead).

Adding up the hash code of the key and the value is not, however, because that produces the false match as demonstrated above, as adding doesn't guarantee the uniqueness of the pairs of keys and values.

Something like this should fix it in the HashMap implementation:

HashMap.prototype.hashCode = function () {
  return this.hamt.fold(function (acc, value, key) {
    return acc + 37 * (Comparison_1.getHashCode(key) * Comparison_1.getHashCode(value));
  }, 0);
};

(Thank you for creating prelude-ts, by the way, our team has gotten a lot of value out of this library and I absolutely love it).

Future Error Type

Hello,
after replacing another fp library with this one, i was missing the error type of a future.
Are there any reasons, why you don't allow to use a future like Future<L, R>?

Implement sequenceAcc for Option

Would it be possible to implement sequenceAcc for Option? Like you have for Either?

Could be used for validation - let's say you have a bunch of functions that - given some input - perform a validation and return Option<TValidationError> .

You want to apply all of those validation functions and get out an Option<TValidationError[]>. If none of the validation functions produce an error then the outcome would be none.

Something like this:

const optionSequenceAcc = <T>(values: Option<T>[]): Option<T[]> => {
  return values.reduce((accum: Option<T[]>, value: Option<T>) => {
    return value.match({
      None: () => accum,
      Some: (error) => Option.some<T[]>([...accum.getOrElse([]), error])
    })
  }, Option.none())
}

Let option.match return two different types

Hey, i was using option.match like this today:

const content = results.match({
  None: () => <Loader />,
  Some: movies => movies.map(movie => <MoviesListItem key={movie.id} {...movie} />)
})

However, the problem is that the None function returns an JSX.Element, which forces the Some function to then also return a JSX.Element, while i actually want it to return an array

So what i propose is to change the types at https://github.com/emmanueltouzery/prelude-ts/blob/master/src/Option.ts#L594 to have two generics, one for each function accepted

I made a typescript playground of it:
https://www.typescriptlang.org/play/index.html#src=type%20Option%3CT%3E%20%3D%20None%3CT%3E%20%7C%20Some%3CT%3E%3B%0D%0A%0D%0Aclass%20None%3CT%3E%20%7B%0D%0A%20%20%20%20constructor()%20%7B%20%7D%0D%0A%0D%0A%20%20%20%20match%3CU%2C%20V%3E(cases%3A%20%7BSome%3A%20(v%3A%20T)%3D%3E%20U%2C%20None%3A%20()%20%3D%3E%20V%7D)%3A%20U%20%7C%20V%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20cases.None()%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0Aclass%20Some%3CT%3E%20%7B%0D%0A%20%20%20%20constructor(private%20value%3A%20T)%20%7B%20%7D%0D%0A%0D%0A%20%20%20%20match%3CU%2C%20V%3E(cases%3A%20%7BSome%3A%20(v%3A%20T)%3D%3E%20U%2C%20None%3A%20()%20%3D%3E%20V%7D)%3A%20U%20%7C%20V%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20cases.Some(this.value)%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0Aconst%20foo%20%3D%20new%20Some(10).match(%7B%0D%0A%20%20%20%20Some%3A%20()%20%3D%3E%20123%2C%0D%0A%20%20%20%20None%3A%20()%20%3D%3E%20%22123%22%0D%0A%7D)%20%2F%2F%3D%3E%20string%20%7C%20number%0D%0A%0D%0Aconst%20bar%20%3D%20new%20Some(10).match(%7B%0D%0A%20%20%20%20Some%3A%20()%20%3D%3E%20123%2C%0D%0A%20%20%20%20None%3A%20()%20%3D%3E%20123%0D%0A%7D)%20%2F%2F%3D%3E%20number%0D%0A%0D%0A

Feat request: .ap (apply) on ADTs

I couldn't find an equivalent function in prelude-ts so please let me know if this exists and I am just missing it.

A common pattern on ADTs (algebraic data types) is ap (short for apply).

From the (Mostly Adequate Guide to Functional Programming)[https://mostly-adequate.gitbooks.io/mostly-adequate-guide/ch10.html#ships-in-bottles]:

ap is a function that can apply the function contents of one functor to the value contents of another.

Examples:
crocks
fp-ts
monet.js

Error calling .map() on an empty Vector

In 0.7.11, if you call .map on an empty Vector, you get:

TypeError: Cannot read property '0' of undefined
  at Vector.map (node_modules/prelude.ts/src/Vector.ts:840:48)

This works fine in master though.

Question: Using Future with Either

I have an example where I need to fetch some data asynchronously and then validate it, which I think lends itself to a type of Future

What do you think to the idea of a new type that consolidates Future with Either?

For example, the Left/Failure of my Future could be a network error.

Without a single type to represent this pattern, I have to map over the Future and then map over the Either, which is quite verbose and I don't really need that level of control.

Seq.indexOf and lastIndexOf proposal

Here's my proposal which I'm ready to implement:

interface Seq<T> {
    indexOf(predicate: (v: T) => boolean): Option<number>;
    lastIndexOf(predicate: (v: T) => boolean): Option<number>;
}

This can be useful for example in model-view updates:

highlight(id: string) {
    items
        .indexOf(item => item.id === id)
        .map(index => views.get(index))
        .ifSome(view => view.highlight());
}

This can be made with zipWithIndex and find but that'll be quite verbose, especially searching for last which would require Seq reversing. Yet this may produce some overhead copying lists.

Make preludeTsContractViolationCb throw an exception instead of a string?

Is it intentional that preludeTsContractViolationCb (

let preludeTsContractViolationCb = (msg:string):void => { throw msg; };
) throws a string instead of an exception?

In my setup (with Mocha), when a test throws a string I don't get a stack trace. When it throws an exception, I do. Thus, running setContractViolationAction((message) => { throw new Error(message); }); before tests makes for much nicer errors.

But if you don't have objections, I think that it would be great to just change preludeTsContractViolationCb to do this by default.

Roadmap to v1.0?

Hello!

First of all, I love your library. It offers exactly what others don't for me and the typings are just good.

I was wondering if there's a roadmap to a v1 release? (if you're even planning on doing one)

I'm already using this in production, but some team members have expressed concerns about the lack of a v1.0.0. I would love to contribute if possible!

Regards,

Clean up package?

You mentioned this several times. Just wondering what's the problem with it? Perhaps I can help.

HashMaps comparison always seems to return the same hash code

Hi,

Given the following

describe("HashMap", () => {
  it("Gives unique hash codes", () => {
    const map1 = HashMap.of(["48", 1], ["49", 2], ["50", 3], ["51", 4]);
    const map2 = HashMap.of(["49", 2], ["50", 3], ["51", 4]);
    const map3 = HashMap.of(["49345678", 2], ["50", 3], ["51", 4]);

    console.log(map1.hashCode(), map2.hashCode(), map3.hashCode());

    expect(map2.hashCode() !== map1.hashCode()).toBeTruthy();
    expect(map3.hashCode() !== map1.hashCode()).toBeTruthy();
    expect(map3.hashCode() !== map2.hashCode()).toBeTruthy();
  });
});

All hash maps are giving me the exact same hash code:


  ● HashMap › Gives unique hash codes

    expect(received).toBeTruthy()

    Received: false

      31 |     console.log(map1.hashCode(), map2.hashCode(), map3.hashCode());
      32 |
    > 33 |     expect(map2.hashCode() !== map1.hashCode()).toBeTruthy();
         |                                                 ^
      34 |     expect(map3.hashCode() !== map1.hashCode()).toBeTruthy();
      35 |     expect(map3.hashCode() !== map2.hashCode()).toBeTruthy();
      36 |   });

      at Object.<anonymous> (src/store/domain/types/DataClass.test.ts:33:49)

  console.log src/store/domain/types/DataClass.test.ts:31
    1696 1696 1696

Test Suites: 1 failed, 1 total

I'd expect some conflicts to be possible given the [comment] above the hashcode function, but since all 3 are returning 1696 even after arbitrary changes, this means we basically can't compare hash maps.

This is on the latest version of PreludeTS.

I'd love to help to fix this but the logic behind generating the hashcode is a bit above my head right now ):

Cannot stringify arbitrary non-POJOs Some.

When nuxt.renderJsonPayloads is enabled in Nuxt 3, it causes the error. Disabling this option in nuxt.config.ts allows the preview to work, but the error still appears in the console. I'm not sure if this is a problem with Nuxt itself, but since it's related to this specific dependency, I decided to create an issue here. Maybe someone else has encountered this issue and found a solution. 🤔

Here is a link to StackBlitz. The only modification I made to the original vitesse-nuxt3 repository is adding prelude-ts and utilizing Option in composables/user.ts for the savedName field. I also updated its usage in pages/hi/[id].vue.

Add .pluck method to Option

In RxJS, there is a pluck operator for mapping items to nested properties, specified by strings.

I think this would nicely fit into Option, so we could write code like this:

interface Nested<T> {
  nested?: { value: T };
}

Option.some<Nested<string>>({ nested: { value: "x" } })
      .pluck("nested", "value")   // returns Option.some("x")

Option.some<Nested<string>>({ })
      .pluck("nested", "value")   // returns Option.none()

// Shouldn't compile since "invalid" is not a property of Nested
Option.some<Nested<string>>({ })
      .pluck("invalid")

Ideally, we should get compiler errors if pluck is passed a string that isn't a valid property of the wrapped type, like in the last example.
See the overloads of pluck in RxJS for inspiration how this can be done.

Replace sed with TS program

First thanks and congrats with 1.0.0 release!

Working on my last PR I had problem with sed: -i option is not standard and it didn't work on my system. I checked what sed is doing — in all places it just replaces by regex. What if I write simple TS script doing the same? I believe it will simplify further contributions.

Add Future.liftXXX

We want a Future.liftXXX-like function as described there and in the rest of the conversation, and suggested by @qm3ster:
#8 (comment)

the only real hurdle left is the name for the function.

Option equality broken

Hi,

stumbled upon a new equality issue

Option.of(Vector.of(12, 2674)).equals(Option.of(null))

yields true

i'm on "prelude-ts": "1.0.5"

Lazy evaluation getOrElseGet pattern Option

Hi @emmanueltouzery.
I really like the idea of this API and like i am a FP fan.

I am using the VAVR in Java 8 projects.

I have a question, the API doesn't provide a "getOrElseGet" in the pattern Option, with a supplier in parameter (allows a lazy evaluation for the OR case).

Have you planned to add it in a futur release ?

Thanks for your help.

Hello

Hello @emmanueltouzery. Congratulations on a very nice looking library! 👍 I recently stumbled upon it and found it to be very interesting.

As you're aware I've created a library with an immutable list. I saw the really clever type you have for partition. I've just implemented it here. Thanks a lot for sharing the idea in your blog post!

I see that you've added List to your benchmarks 😄 I had already done so myself to see how the libraries compare. I'm going to work on improving performance in the cases where List is not as fast as your Vector.

I can see that you have "Non-empty vector?" on the "Wishlist/upcoming features". I have been thinking about adding such a feature to List. But, I'm now sure if it's worth it. What do you think? When does the feature help?

Option.ofNullable(0) returns None

Option.ofNullable uses Javascript "truthiness" as its predicate, instead of comparing against null.

The result of this is that Option.ofNullable(0) returns None, instead of the expected value Some<0>

Option.getOrThrow() should take Error as argument

Option.getOrThrow() currently takes a string as its argument. I think that it should take an Error instance, because throwing bare strings is generally considered poor Javascript coding practice.

Current method:

getOrThrow(message?: string): T & WithEquality {
    throw message || "getOrThrow called on none!";
}

Suggested:

getOrThrow(error?: Error): T & WithEquality {
    throw error || new Error("getOrThrow called on none!");
}

Validation - accumulating errors with Either

I've got some code like this

// We're populating a FinancialTransaction bit by bit

// Start in the "right" state with just the transactionId populated
const initial = Either.right<TransactionParseFailure, Partial<FinancialTransaction>>({ transactionId });

// Curry the raw-data in - populateAmount takes a partial financial transaction and returns either 
// - a TransactionParseFailure (left) or 
// - a partial financial transaction with the amount field populated (right)
const populateAmount = PopulateAmount(rawData);

// Curry the raw-data in - populateTransactionDate takes a partial financial transaction and returns either 
// - a TransactionParseFailure (left) or 
// - a partial financial transaction with the date field populated (right)
const populateTransactionDate = PopulateTransactionDate(rawData);

return initial
  .flatMap(populateAmount)
  .flatMap(populateTransactionDate)
  .map(PopulateOptionalFields);

However I'd like to change this so that we accumulate the errors - at the moment, it stops as soon as it ends in a left state. I think normally I'd do this with a Validation type, however prelude-ts is missing one currently.

I can't seem to get my head around how to achieve this with Either.sequenceAcc or Either.liftApAcc

Package name issue

I am trying your library:

import { Vector } from 'prelude.ts';

But I got this error:

src/index.ts:5:24 - error TS2691: An import path cannot end with a '.ts' extension. Consider importing 'prelude' instead.

So I tried only prelude as it suggests and that crashes with this:

src/index.ts:5:24 - error TS2307: Cannot find module 'prelude'.

When I was installing the package I thought the name is a bit weird, but I didn't expect it is not supported by TypeScript.

TS: 3.1.3
prelude.ts: 0.8.1

Error calling findAny on an empty HashMap

import { HashMap } from 'prelude.ts';
HashMap<string, string>.empty().findAny(() => true);

Results in:

TypeError: this.hamt.entries is not a function
    at EmptyHashMap.HashMap.findAny (node_modules/prelude.ts/src/HashMap.ts:381:53)
    at Object.<anonymous> (test.ts:2:33)

Vite util.inspect

Hi, I recently switched to vite for building but get an error "util.inspect is not defined" from Value.ts when opening in the browser. I briefly tried looking why say webpack polyfills util.inspect but vite does not. But then on the node documentation for util.inspect https://nodejs.org/api/util.html#util_util_inspect_custom it mentions that the symbol is also available at Symbol.for("nodejs.util.inspect.custom").

So rather than try and deal with polyfills, I just switched prelude-ts to use Symbol.for which in the browser will just create a new symbol while on node will find the correct symbol.

I'll admit I just made the change directly in node_modules just to get by since I am just evaluating switching to vite. I can create a real pull request if you like.

Future API changes

continuing the discussion from #8

@qm3ster => all good points, food for thought. Note that prelude.ts has a Stream collection type and yes it works as you described. I would consider renaming the on* methods and have them possibly returning void instead of returning the Future, but I'm not sure for the name right now (maybe onFailed=>ifFail, onSucceeded=>ifSuccess, onCompleted=>match or matchValue), or even if that's really the good path forward.
That's also connected to some changes I'm working on in these methods regarding error handling.

And besides that I think yes probably map & flatMap should be lazy, and we can also add an explicit. .trigger() (with in apidoc that you don't need it if you do await, or if you do X or Y and so on). The trigger would likely return void.

Are ideas, PRs accepted?

Hi, first I'd like to say your great lib is a real relief after all these unnatural for TS X.compose(..., ...)(data). Operating collections in Scala-style is a real pleasure. That's huge and valuable work, thanks.

Now the question is — do you welcome suggestions and code? If you do, I'd create issues whenever I have an idea (I have some), so they can be discussed; then proceed with PR if an idea is accepted. What are your thoughts?

"Cannot read property '0' of undefined" on repeated Vector.appendAll

This code:

import { Vector } from 'prelude.ts';

let v = Vector.ofIterable(Array(15).fill(1));

for (let i = 0; i < 100; i += 1) {
  console.log(i);
  v = v.appendAll(Array(1000).fill(1));
}

Will fail after 86 iterations with:

TypeError: Cannot read property '0' of undefined
    at Vector.getLastNode (node_modules/prelude.ts/src/Vector.ts:279:31)
    at Vector.appendAllArrays (node_modules/prelude.ts/src/Vector.ts:457:34)
    at Vector.appendAll (node_modules/prelude.ts/src/Vector.ts:419:25)

Allow equality comparer in the Set/Map constructor

There maybe a way already to allow this. I would like to be able to use interfaces for the elements. At the moment I believe that would mean having equals and hashCode on the interface which would then mean creating an instance of the interface would require setting those each time.

If the collection implementations could take an EqualityComparer which has those 2 methods then I believe I could use interfaces.

Another advantage is that I could then have different Equality for the same interface. My main Interface is:

interface Fact { subject: string, property: string , value: string }

Depending on the circumstance any of the properties could be the key or any combination also.

Thanks.

Documentation - Replace "Set, Map and equality" from readme with a link to the Wiki and use "Prelude−ts user guide" as Wiki home

As per title, I think the "Set, Map and equality" paragraph in the readme is redundant. The same thing can be found in the Wiki.

Also, in the Wiki it's a bit uncomfortable having to click on the "Prelude−ts user guide" link to read something. Wouldn't it be better to make it the Wiki home?

Edit: for the Predicate Wiki paragraph, maybe you can add this real-world example:
Before:

let filtered = jobs.filter(job => filteredDomains.includes(job.domain))

if (selectedTagsIds.length) {
  filtered = filtered.filter(job => job.tags.some(tag => selectedTagsIds.includes(tag)))
}

const jobNameFilter = filteredJobName.trim()

if (jobNameFilter) {
  filtered =
      filtered.filter(job =>
          job.name.toLowerCase().includes(jobNameFilter.toLowerCase()))
}

return filtered

After:

const jobNameFilter = filteredJobName.trim()
const predicates = Predicate.allOf(...[
  (j: Job) => filteredDomains.contains(j.domain),
  ...selectedTagsIds.length() ? [(j: Job) => j.tags.some(t => selectedTagsIds.contains(t))] : [],
  ...jobNameFilter ? [(j: Job) => j.name.toLowerCase().includes(jobNameFilter.toLowerCase())] : []
])

return jobs.filter(predicates)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.