question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

function equivalent of "do" notation

See original GitHub issue

Let’s consider a problem which a hypothetical do function might help us to solve:

Given an object, return the square root of the number represented by the string at path a.b.c. Do not assume, however, that the path a.b.c will exist.

Here’s the obvious naive solution:

// naive :: Object -> Number
const naive = o => Math.sqrt(parseFloat(o.a.b.c));

This won’t handle all the following inputs:

  • {a: {b: {c: '2.25'}}}
  • {a: {b: {c: 'blah'}}}
  • {a: {b: {}}}
  • {a: {}}
  • {}

This is how I would solve this problem today:

// safe1 :: Object -> Maybe Number
const safe1 = R.pipe(
  S.get('a'),
  R.chain(S.get('b')),
  R.chain(S.get('c')),
  R.chain(S.parseFloat),
  R.map(Math.sqrt)
);

With two small changes we can make this more uniform:

// safe2 :: Object -> Maybe Number
const safe2 = R.pipe(
  S.Just,
  R.chain(S.get('a')),
  R.chain(S.get('b')),
  R.chain(S.get('c')),
  R.chain(S.parseFloat),
  R.chain(R.compose(S.Just, Math.sqrt))
);

If we then changed the type from Object -> Maybe Number to Maybe Object -> Maybe Number we could remove the first step of the pipeline:

// safe3 :: Maybe Object -> Maybe Number
const safe3 = R.pipe(
  R.chain(S.get('a')),
  R.chain(S.get('b')),
  R.chain(S.get('c')),
  R.chain(S.parseFloat),
  R.chain(R.compose(S.Just, Math.sqrt))
);

Now we have a form which can surely be abstracted! Given a list of functions we want to apply R.chain to each, then apply R.pipe to the list as positional arguments:

// $do :: Monad m => [(a -> m b), (b -> m c), ..., (y -> m z)] -> m a -> m z
const $do = fs => R.apply(R.pipe, R.map(R.chain, fs));

This can be written point-free:

// $do :: Monad m => [(a -> m b), (b -> m c), ..., (y -> m z)] -> m a -> m z
const $do = R.pipe(R.map(R.chain), R.apply(R.pipe));

Let’s rewrite safe3 in terms of $do:

// safe4 :: Maybe Object -> Maybe Number
const safe4 = $do([
  S.get('a'),
  S.get('b'),
  S.get('c'),
  S.parseFloat,
  R.compose(S.Just, Math.sqrt),
]);

$do works for any Monad, and should reduce demand for “composed-chain” functions such as S.gets.

What do you think? Shall we add this? If so, what should it be named? S.do is problematic since do is not a valid identifier. S.$do is pretty ugly. Does do go by other names?

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:30 (23 by maintainers)

github_iconTop GitHub Comments

3reactions
buzzdecafecommented, Jun 17, 2015

They’re all specific cases of a more general Semigroupoid idea.

I recall you and @scott-christopher discussing that in the gitter room. i may take a whack at unifying our many composers into one.

Which raises the thought: A good name for a javascript composition lib would be Bach.js

1reaction
benperezcommented, Jun 17, 2015

Oh, duh. 🐐

The only limitation I see here is that this form of do notation only really allows you to feed through a single monadic value. You lose the ability to bind different variables to different monadic values in the same do expression like the following example:

foo :: Maybe String  
foo = do  
    x <- Just 3  
    y <- Just "!"  
    Just (show x ++ y)
Read more comments on GitHub >

github_iconTop Results From Across the Web

Haskell/do notation - Wikibooks, open books for an open world
Contents. Using do blocks as an alternative monad syntax was first introduced way back in the Simple input and output chapter. There, we...
Read more >
Do notation considered harmful - HaskellWiki
The do notation hides functional details. This is wanted in order to simplify writing imperative style code fragments. The downsides are that: ...
Read more >
Do notation - Aelve Guide | Haskell
Do notation is syntactic sugar for writing code using monads, eventually being replaced by uses of >> or >>= by the compiler.
Read more >
Learn the use of do notation in Haskell - eduCBA
Do notations are simply designed to handle the IO operations in Haskell. To represent the do notation, we can simply use the 'do'...
Read more >
do_notation - Rust - Docs.rs
A line containing a single expression with a semicolon is a valid statement and has the same effect as _ <- expr ....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found