Skip to content

Instantly share code, notes, and snippets.

@dherman
Last active June 30, 2021 14:21
Show Gist options
  • Save dherman/1c97dfb25179fa34a41b5fff040f9879 to your computer and use it in GitHub Desktop.
Save dherman/1c97dfb25179fa34a41b5fff040f9879 to your computer and use it in GitHub Desktop.

Motivation

  • expression-oriented programming one of the great advances of FP
  • expressions plug together like legos, making more malleable programming experience in-the-small

Examples

Write in an expression-oriented style, scoping variables as locally as possible:

let x = do {
  let tmp = f();
  tmp * tmp + 1
};

Use conditional statements as expressions, instead of awkward nested ternaries:

let x = do {
  if (foo()) { f() }
  else if (bar()) { g() }
  else { h() }
};

Especially nice for templating languages like JSX:

return (
  <nav>
    <Home />
    {
      do {
        if (loggedIn) {
          <LogoutButton />
        } else {
          <LoginButton />
        }
      }
    }
  </nav>
)

Tennant's Correspondence Principle

  • key refactoring principles:
    • do { <expr>; } equivalent to <expr>
    • (do { <stmt> };) equivalent to { <stmt> }
  • this semantic transparency is demonstrated by the semantics:
    1. Return the result of evaluating Body.

Further considerations

How to avoid either parsing conflict in statement context with do-while, or dangling-else type of ambiguity:

do do f(); while (x);

I have several alternatives I intend to explore here.

@Jamesernator
Copy link

@ecbrodie There's no reason that wouldn't work, the completion value of if is already well defined, basically you see the result of anything a do-block could do just by eval-ing the body e.g.:

const x = eval(`
    if (true) {
        'banana'
    }
}
x // 'banana'

const y = eval(`
    if (false) {
        'banana'
    }
}

y // undefined

@streamich
Copy link

streamich commented Sep 9, 2017

Regarding this JSX example:

return (
  <nav>
    <Home />
    {
      do {
        if (loggedIn) {
          <LogoutButton />
        } else {
          <LoginButton />
        }
      }
    }
  </nav>
)

I got triggered so badly on this:

Especially nice for templating languages like JSX...

First, the ternary expression is million times better in this situation:

return (
  <nav>
    <Home />
    {loggedIn ? <LogoutButton /> : <LoginButton />}
  </nav>
)

Second, no need to use JSX, just use the HyperScript function h, which makes it another million times better:

return h('nav',
  h(Home),
  loggedIn ? h(LogoutButton) : h(LoginButton),
);

Or JSON-ML (hint: JSON is built into JavaScript by default; no need to use the defunct XML syntax in JavaScript):

return ['nav',
  [Home],
  loggedIn ? [LogoutButton] : [LoginButton],
];

Reported for this example.

just kidding ;)

@drhumlen
Copy link

Is there any activity on this? Or similar proposals elsewhere I could look at or try out?

I need this really badly -- especially when working with JSX.

@streamich A ternary is pretty nice when there's only 2 branches (true or false), but if there's 3-4-5 it quickly becomes completely unreadable and you're forced to make a helper function with return to avoid using a temporary variable.

One could argue that splitting things into functions is "right" anyway, but I want refactoring into functions/consts a conscious decisions, not something I have to do because of language restrictions. Inline is often easier to read than having to jump back and forth between intermediary helper functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment