GithubHelp home page GithubHelp logo

monet / monet.js Goto Github PK

View Code? Open in Web Editor NEW
1.6K 27.0 116.0 2.11 MB

monet.js - Monadic types library for JavaScript

Home Page: https://monet.github.io/monet.js/

License: MIT License

JavaScript 90.19% TypeScript 9.50% Shell 0.31%

monet.js's Introduction

monet.js

For people who wish they didn't have to program in JavaScript. documentation

Introduction

Monet is a library designed to bring great power to your JavaScript programming. It is a tool bag that assists Functional Programming by providing a rich set of Monads and other useful functions.

This library is inspired by those that have come before, especially the FunctionalJava and Scalaz projects.

While functional programming may be alien to you, this library is a simple way to introduce monads and pure functional programming into your daily practices.

Documentation

Full detailed documentation can be found here

Installation

NPM

npm install monet --save

# or to install a specific version
npm install [email protected]

Download

Download the zip or tar ball.

Browser

Simply download and add to your html pages. You can also include monet-pimp.js which contains extra functions on the Object.prototype for creating monads.

<script src="monet.js"></script>
<!-- Optionally -->
<script src="monet-pimp.js"></script>

Contents

The Maybe type is the most common way of representing nothingness (or the null type) with making the possibilities of NullPointer issues disappear.

Maybe is effectively abstract and has two concrete subtypes: Some (also Just) and None (also Nothing).

Either (or the disjunct union) is a type that can either hold a value of type A or a value of type B but never at the same time. Typically it is used to represent computations that can fail with an error. Think of it as a better way to handle exceptions. We think of an Either as having two sides, the success is held on the right and the failure on the left. This is a right biased either which means that map and flatMap (bind) will operate on the right side of the either.

Validation is not quite a monad as it doesn't quite follow the monad rules, even though it has the monad methods. It that can hold either a success value or a failure value (i.e. an error message or some other failure object) and has methods for accumulating errors. We will represent a Validation like this: Validation[E,A] where E represents the error type and A represents the success type.

An immutable list is a list that has a head element and a tail. A tail is another list. The empty list is represented by the Nil constructor. An immutable list is also known as a "cons" list. Whenever an element is added to the list a new list is created which is essentially a new head with a pointer to the existing list.

Much like the immutable list, a Non Empty List can never be empty. It implements the comonad pattern. It has a guaranteed head (total) and a guaranteed (total) tail.

The IO monad is for isolating effects to maintain referential transparency in your software. Essentially you create a description of your effects of which is performed as the last action in your programme. The IO is lazy and will not be evaluated until the perform (alias run) method is called.

The Reader monad is a wonderful solution to inject dependencies into your functions. There are plenty of great resources to get your teeth into the Reader monad such as these great talks.

The Reader monad provides a way to "weave" your configuration throughout your programme.

The Free monad is a monad that is able to separate instructions from their interpreter. There are many applications for this monad, and one of them is for implementing Trampolines, (which is a way to make recursion constant stack for languages that don't support tail call elimination, like JavaScript!).

Please see Ken Scambler's excellent talk and example project to get an in-depth understanding of this very useful monad.

Author

Written and maintained by Chris Myers @cwmyers and Jakub Strojewski @ulfryk. Follow Monet.js at @monetjs.

monet.js's People

Contributors

alexrex avatar amilajack avatar bskyb-myersch avatar char0n avatar crisson avatar customcommander avatar cwmyers avatar danielfgray avatar desfero avatar emmanueltouzery avatar eskimoblood avatar igormoreno avatar innovimax avatar jdh8 avatar jleider avatar kpudlik avatar krjackso avatar lukasztheprogrammer avatar maximgoncharuksw avatar mlrv avatar nikital avatar parambirs avatar raine avatar rparree avatar sobolevn avatar tomecko avatar treybrisbane avatar ulfryk avatar wojciechp avatar yemi 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

monet.js's Issues

Free monad

Hello, first its great work, love how far you pushed with monads here.. :-)

I see.first time Free implementation in. Js and here comes my question. Example is.bit scarce.
Could you provide some example of how to use this implementation to build some usable AST and interpreter for it?

Would much appreciate and i.guess docs would benefit too. :-)

TypeScript definitions

Is there any possibility that you will add TypeScript definitions of this great library to DefinitelyTyped or to this repository ?

I would feel happy to help with that :)

curry and map

Hello,

I'm trying this:

var add = function(a,b) {
  return a+b;
}.curry();
var increment = add(1);
var arr1 = [100, 200, 300, 400, 500];
var arr2 = arr1.map(increment); 

I expect an array of Integer for arr2 : 101,201,301,401,501 but I get an array of function instead

Then it's ok If I do this arr2 = arr1.map((item)=>increment(item));

Or this is ok

var incr = function(x) { return x + 1; }
arr1.map(incr) // 101,201,301,401,501

what I missed (misunderstood) with curry?

thx 😄

export to single object in the browser

When using in the browser, every monad is added to the window object.

In keeping with the standard for libraries, I believe it should instead only set window.Monet and each type can then be accessed as a property of Monet.

Similar to how you have monet-pimp.js you could have monet-global.js which allows people to keep using it in the current fashion.

Function.prototype extensions

Shouldn't they be an opt-in by using monet-pimp? Polluting native objects shouldnt be made by default in my opinion. Its just asking for trouble, especially in my use case when I do not have full control about environment my script is working in.

Maybe.fromFalsy operator

Hello,

I've noticed that Maybe.fromNull(val) works only for null or non-null values. In my case I wanted to check whether value is an empty string (perform some mappings etc.) or not (just return another value). The most elegant way of doing this is to use .filter:
Maybe.fromNull('').filter(Boolean).

My suggestion is to make an additional operator like Maybe.fromFalsy(val) which checks falsy values:

Maybe.fromFalsy('')
    .map(val => val.concat('X'))
    .orJust('ElseString') // 'ElseString'

List size

// current output is
List().size()
// => 0 

List("a").size()
// => 0

List("a", List("b")).size()
// => 1

List("a", List("b", List("c"))).size()
// => 2

Reader.of question

I'm just getting into monads in JS and been playing around with few implementations of Reader and noticed that monet's Reader.of expects a function. Some libs can wrap a value directly into the default context. I wonder if there's reason for this inconsistency, or is there simply no standard way to implement Reader.of?

Here's a small example I came up with in livescript.

New bugfix release

It's been sometime since the last patch release. Since development has slowed, can you mint 0.8.7 and publish it to npm?

Repository workflow

Hi Jakob (and everyone),

Up until now I have used the git-flow workflow to manage the development and release of monet. I've had a long running master and develop branches and short lived "feature" branches. Feature branches would get merged into develop and once develop was stable I would merge it into master and do a release from there.

I am happy to review this workflow. I think it's a bit confusing for the community to know which branch to send their PRs to. I'm considering retiring the develop branch permanently.

What do you think?

Some questions about differences in IO examples

First of all, thanks for a great lib!

I'm trying to rewrite parts of our application using ramda/monet. I was looking through some of your resources when I got a little confused about the IO monad.

In the IO example from the docs there is a read and a write function, both are IO's of impure functions.

In the IO.html example from the examples folder, however, there are a bunch of impure functions that are not wrapped in IO's (e.g. getText, setText, setHtml etc.).

I know that a function like getTextForId only maps getText over the returned jQuery object from getId which eventually returns an IO, meaning that the impurity is only happening inside of the IO.

So to my question: is it okay to define impure functions as long as they're only being used inside an IO or why are the examples in the docs different form the IO.html example in this way?

0.9 release

There are a few features in that milestone that I'd love to have. Releasing any time soon? :)

Maybe.foreach method

Hi, I recently started using this great library. I ran into an issue when trying to do some logic like

if (maybe.isSome) doThing(maybe.some())

The map method would be elegant, but throws on functions that return undefined. I'd like to add a foreach method to the basic monad type, with a signature like

foreach(fn: (val: T) => void): void

Before I go ahead with implementing that - is this something that would be beneficial?

Fix bower.json

invalid-meta The "main" field has to contain only 1 file per filetype; found multiple .js files: ["src/main/javascript/monet.js","src/main/javascript/monet-pimp.js"]

Fix errors so they provide more information

Now when for example Some(null); is called the only information we get with thrown error is "Illegal state exception" and stack. Would be nice if it informed that it's Monet error and that it's connected with Maybe :)

illegal state exception on Maybe.ap() invocation with null returning function

hello

I am really new to the monad universe, and in fact using Monet.js to explore it.

I stumbled on an "Illegal state exception" while running

function nullFunc() { return null }
Some("a").ap(Some(nullFunc)); // throws "Illegal state exception" from Maybe.fn.Maybe.init

The problem seems to come from the fact that the map function listed hereafter composer _this.of_ with fn (my nullFunc).

Looking though the spec I did not see any requirement that ap() should be passed a non-null returning function. Did I miss something

Why use this.of and not this.fromNull in map ?

var map = function (fn) {
        return this.bind(this.of.compose(fn))
    }

Sorry I didn't proposed the PR, but I have miles to cover and the subject before

Clarification with signature and implementation of bind/flatMap of MonadT

Hi, Am a new guy to Monad Transformers, so help me clarify if I'm mentioning something wrong, I was looking at the implementation of bind of MonadT ( https://github.com/cwmyers/monet.js/blob/master/src/main/javascript/monet.js#L591-L595 ), and looking at the signature of bind(from https://en.wikibooks.org/wiki/Haskell/Monad_transformers ), isn't it the case that bind should take as argument, a function which takes an A => MonadT[B] ?

(>>=) :: MaybeT m a -> (a -> MaybeT m b) -> MaybeT m b

The spec given https://github.com/cwmyers/monet.js/blob/ebdffd1bf64d26b00f75bf01490720256eb70396/src/test/javascript/monad_transformer_spec.js#L28-L31 also is a function which flatMap's over the inner Monad, without considering the outer monad. Am I getting something wrong? Help clarify?

React problem with require('monet')

Hi, maybe you can help me. I've developed a backend logic using monads and I was exploring with react.js. Everything goes well until I´ve stared to require the monad module for my backend.
I'm rendering the react on server side, and somehow when I require the monet module I always get a "Invariant Violation: pp.render(): A valid ReactComponent must be returned.".
I know that the the error is sent by react, but since the problem only happens when a require the monet module, maybe you could know the asnwer. Thanks.

publish in npm

It would be convenient if monet.js was available in npm too.

Reader monad example

The Reader monad example does not work as expected:

If we have functions (copied from example):

function createPrettyName(name) {
    return Reader(function(printer) {
        return printer.log("hello " + name)
    })
}

function render() {
    return createPrettyName("Tom").map(function (s) { return "---"+s+"---"})
}

Calling render().run(console) logs hello Tom and returns "---undefined---"…

Support with async await

I have been using babel (async await features) along with monet.js to help me write code in declarative style. I have used the Either monad to represent a success/failure condition. Below is some pseudo code.

async function(response) => {
    // return Either monad
    let eitherResult = await generateSessionKey(url);
    eitherResult.map((sessionKey) =>  await callApi(sessionKey))
        .cata((errorResult) => response.status(404).send(errorResult),
                 (success)      => response.sendJson(success));
}

This does not work since map function returns immediately and an empty response is written back. Is it possible to have a version of map function that honors Future/Promise values?

Maybe.Some bind returning an Either Monad

Hi

I was playing around with monet and found it pretty exciting. However, there's an issue I have when I want to return a different Monad inside a bind than the "outer" Monad.

Example:
Assume that I have a Maybe Monad (Some or None), and I want to bind a function that returns an Either (Left or Right), depending on some contrived condition:

aMaybe.bind(function(val){
    if (val.length == 0) {
        return Either.Left("Empty string");
    } else {
        return Either.Right(val);
    }
})

If the Maybe is Some, then I'll actually get an Either back. However, if the Maybe is None, I'll stay in the Maybe Monad as the bind is not evaluated.

I'm pretty sure this is not allowed; i.e. by convention the bind should probably return the same Monad type as the "current" Monad. However, how should I then handle situations where I actually would like to execute code inside a bind that would make sense to return an Either? How would one actually go about solving such an issue with Monet?

Sorry if this is common knowledge when working with Monads a lot. It's a new topic for me and I want to make sure I do the right thing. If there happen to be resources about this, I'd be happy even if you just reply with a one-line link to the answer.

IO that actually does... io

Hey, you have an IO type, nice.

Wouldn't it be nice if it would be able to actually perform IO (like wait for the user to enter a string, make a web request, read a file in node and so on)?

All it currently does is emulate unsafePerformIO - wouldn't it be useful for it to do IO?

Possibility to shorten these type parameters declarations?

When using e.g. Either from with typescript it's always required to put both type parameters when creating instance e.g.

  function activateUser(user: User): Either<Err, User> {
     // ... do stuff here
     if(cannotBeActivated(user)) {
       return Left<Err, User>(Err.of('Cannot be activated');
     }
     return Right<Err, User>(user)
   }

Notice this kind of redundant type parameters in both return statements (Left<Err, User> and Right<Err, User>).

I wonder if there is a way to provide some kind of type alias, like

does-not-compile code ahead:

    import {Either, Right, Left} from "monet";
    type Result = Either<Err, User>
    // ...
    return Result.Right(user)

gives TS2693: 'Result' only refers to a type but is being used as a value here

    import {Either, Right, Left} from "monet";
    type Ok = Right<Err, User>
    type NotOk = Left<Err, User>
    // ...
    return Ok(user)

gives TS2304: Cannot find name Right

I see why these can be wrong, so my question is whether it's possible (and if so, how?) to achieve similar result that compiles and makes these definitions shorter? I guess it's more of a question to @ulfryk as he's the one delivering TS goodies to monet :)

IO function not working as expected

Hi,

var read = IO(function (id) { return $(id).text() });

var write = function(id) {
    return IO(function(value) {
        $(id).text(value)
    })
};

var toUpper = function (text) { return text.toUpperCase() };
var changeToUpperIO = read("#myId").map(toUpper).flatMap(write("#myId"));

changeToUpperIO.run();

Gives me the error: read is not a function. This is because it's the object IO.fn.IO.init

typescript bindings & strict null checks

When using the strict null checks mode in typescript, null & undefined are separated from the other types.

In other words, the signature of fromNull is definitely wrong:

fromNull<V>(val: V): Maybe<V>;

it should be:

fromNull<V>(val: V|null): Maybe<V>;

and maybe we also want to allow undefined (mapping it to None):

fromNull<V>(val: V|null|undefined): Maybe<V>;

That also mean that orSome(null) will not compile. We could do:

orSome(val: T|null|undefined): T|null|undefined;

or we do:

orNull(): T|null

What do you think? Would you accept a PR regarding that (but then, implementing which variant?)

Equivalents of the Haskell functions `maybe` and `either`

Would be useful to have functions like the Haskell functions maybe :: b -> (a -> b) -> Maybe a -> b and either :: (a -> c) -> (b -> c) -> Either a b -> c (both of which are documented at http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html).

There are a number of equivalent possible ways of implementing the former function using existing functions; perhaps:

Maybe.maybe = (ifNone, mapIfSome, m) => m.map(mapIfSome).orElse(Maybe.Some(ifNone)).some()

The latter is simply a useful alias that might be more memorable to anyone with Haskell experience than cata. I'm perhaps not quite good enough at category theory, but I think maybe is also a catamorphism, so perhaps that should also have a name of cata too.

Human-readable string representation

Hello,
I think it would be nice to have proper string representation of monet data types in terms of .toString() / .inspect() methods. In particular, I think these constructs should represent themselves:

  • Just(1)
  • Left(2)
  • Right(3)
  • Success(4)
  • Fail(5)
  • Identity(6)

Moreover, I'd represent Nothing(), List.fromArray([1, 2, 3]) and NEL.fromArray([1, 2, 3]) as Nothing, List(1, 2, 3) and NEL(1, 2, 3), respectively.

I'd happily contribute, but I'd rather hear your opinion first. @cwmyers, @ulfryk - what do you think?

Support for Promises as Monads

This would be a nice feature to include into the library at some point. Promises are great, but what I'm not sure is if they completely follow monadic laws

Io example (pt2)

So following @puffnfresh advice here #14 , i now have the example working up until flatMap. At which point i recieve:

Users/emris/src/js/monads/node_modules/monet/src/main/javascript/monet.js:623
                return fn(self.effectFn()).run()
                       ^
TypeError: object is not a function

with this code

require('monet')

function read() {
    return IO( function (){ return "A message" } )
}

function log(logFn) {
    return IO(function(value) {
        logFn(value)
    })
}

function toUpper(text) { return text.toUpperCase() }

var someIo = read().map(toUpper).flatMap(log(console.log))
someIo.run()

I have custom patched monet to actually modify the global node environment, so that it works as it does in the browser:

monet.js:12
turns into

module.exports = factory(GLOBAL);

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.