Git Product home page Git Product logo

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

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

Stargazers

Andy Lu avatar  avatar Shaun Culver avatar Denis avatar Shitty Girl avatar Jean Pierre Ortiz Murcia avatar laurent bernabé avatar  avatar Abhijit avatar Budhaditya avatar Ernst Salzmann avatar Gustave avatar Jason Manuel avatar  avatar Alexandru Ghiura avatar Adam Biggs avatar  avatar Serge Bedzhyk avatar Cristian A. Enguídanos Nebot avatar Anbarasu  avatar Ilya Medvedev avatar omar avatar Siddharth Gelera (reaper) avatar  avatar Alexander Chashchin avatar MeePwn avatar Noor Mohamed avatar Markus Strasser avatar Stephen N. avatar pedoc avatar Shivaprasad Bhat avatar Andrew Choly avatar Sean  avatar Milan Krupa avatar 02020 avatar Gabor Dolla avatar Jamie Mason avatar Keisuke Takeke avatar Daniele Dellafiore avatar  avatar Pedro Luiz avatar  avatar Renato Gama avatar André Carvalho avatar simon avatar Rich Ramalho avatar Michael Oberegger avatar Wondong Kim avatar Simon Kunz avatar  avatar Xavier Zhou avatar Gerald Yeo avatar Oscar avatar Nikita Deryushev avatar Baptiste Langlade avatar Sutee S. avatar pius712 avatar Jintao Koong avatar George Lima avatar Hasi Hays (PhD) avatar  avatar Olle Mattsson avatar envov avatar 捶爆丶憨憨猪 avatar Adidi avatar  avatar Thet Khine avatar SeungHwan-Lee avatar Yoichiro Hasebe avatar Jon Schoning avatar Famer avatar Cristian Velasquez Ramos avatar Tramaine Gillus avatar Eugene Schemelev avatar ZXT avatar Song lanlan avatar YOUNGJOO-YOON avatar  avatar Matthias Seemann avatar Michael C avatar Manrike Villalobos Báez avatar mengo avatar Young-Chen Chang avatar Blake Estes avatar NNashwin avatar Cyril Dever avatar  avatar Jack Walden avatar Chris Dinh avatar Giovanni Lituma avatar Nguyễn Trọng Vĩnh avatar Robert Grigorian avatar Aklil avatar  avatar why520crazy avatar Alex Chugaev avatar Roni avatar fedi abdouli avatar Andrew Moss avatar Yaroslav avatar

Watchers

Stig Kleppe-Jørgensen avatar Isaac A. Dettman avatar evandrix avatar Xian avatar Matthias Seemann avatar  avatar Philippe Charrière avatar Patrick Laplante avatar timelyportfolio avatar James Cloos avatar Paul Bouzakis avatar Mateusz Kulesza avatar Erik Schoel avatar  avatar Denis Stoyanov avatar moro-programmer avatar  avatar  avatar  avatar Nícolas Deçordi avatar  avatar Joshua Derocher avatar Jakub Kriz avatar Hong duc avatar alex.zeng avatar James Saballegue avatar allnulled avatar

monet.js's Issues

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.

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 :)

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?

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?

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?

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?

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.

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

publish in npm

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

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.

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

0.9 release

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

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 :)

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.

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---"…

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?

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 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);

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

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 😄

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'

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?

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.

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"]

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?

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 :)

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

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?

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?)

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.