Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maintain JS syntax #1

Closed
edmulraney opened this issue Feb 2, 2017 · 12 comments
Closed

Maintain JS syntax #1

edmulraney opened this issue Feb 2, 2017 · 12 comments

Comments

@edmulraney
Copy link

Hey, cool project. I might be missing the point of the pattern guard but could we not do the same thing in plain JS:

const guard = args => pattern => pattern.find(pair => pair[0](args))[1]

// test
const [a, b, c] = [1, 3, 7]

const result = guard({a, b, c})([
  [({a,b}) => a > b, 1337],
  [({b,c}) => b > c, 999],
  [({a,c}) => c > a, 42],
  [({b,c}) => c > b, 11],
  [() => true, 'default value']
])

console.log(result) // 42
@yamafaktory
Copy link
Owner

Hi @edmulraney,

Thanks a lot for your feedback! Of course, you can do it this way but IMHO your solution is a lot more verbose and starts to be really hard to read.

My point was to re-implement the Haskell pattern guard syntax, which I find quite clean and expressive.

By the way, I'm not really sure if what you suggest is really an issue (more an alternative implementation which is totally fine). Do you mind if we close it?

@edmulraney
Copy link
Author

Yeah sorry, close this 👍
I was curious about the tradeoff of using template syntax vs plain JS.

Cheers @yamafaktory 😄

@yamafaktory
Copy link
Owner

Thanks @edmulraney 🍻

@edmulraney
Copy link
Author

I had a quick go at reducing verbosity and came up with this monstrosity:

const [a, b, c] = [1, 3, 7]

const destructProps = args => Object.keys(args).join(",")
const buildPredicateFn = (args, pattern) => new Function('', `const {${destructProps(args)}} = ${JSON.stringify(args)}; return ${pattern}`)
const guard = args => patterns => patterns.find(pair => buildPredicateFn(args, pair[0])())[1]

const result = guard({a,b,c})([
  ['a > b', 1337],
  ['b > c', 999],
  ['c > a', 42],
  ['c > b', 11],
  [true, 'default value']
])

console.log(result) // 42

Possible alternative to running VM, and would run in the browser.

@yamafaktory
Copy link
Owner

@edmulraney This sounds really great 👍.

As I want to stick with the Haskell pattern guard syntax and with a tagged template literal, I've modified your code as follow https://jsfiddle.net/yamafaktory/92mgnnpo/.

I think this could definitely be a great improvement as it would run in the browser (if supported, or could be transpiled). But in this case, maybe you can create a PR for what you did?

@yamafaktory yamafaktory reopened this Feb 2, 2017
@edmulraney
Copy link
Author

edmulraney commented Feb 2, 2017

Ah cool, yeah if you're interested I can modify what I've done to work with the guard syntax you're after.
Could also make it generate es5 so it wouldn't need to be transpiled/ran in a modern browser.

(as a PR)

@yamafaktory
Copy link
Owner

Actually not that much needs to be done, the quick fiddle I did reusing your code mixed with mine is already working. We can drop the class in https://github.com/yamafaktory/pattern-guard/blob/master/index.js#L3 and simply export a function like you did.

@edmulraney
Copy link
Author

Awwesome 👍 I think the only issue was that some browsers will fail on the es6 stuff (const {destructure}).

@edmulraney
Copy link
Author

edmulraney commented Feb 2, 2017

Had a go at making it parse the guard as a string just using string manipulation: https://goo.gl/crHzUo
Might be a bit faster than the regex.

const [a, b, c] = [1, 3, 7]

const destructProps = args => Object.keys(args).join(",")
const buildPredicateFn = (args, pattern) => new Function('', `const {${destructProps(args)}} = ${JSON.stringify(args)}; return ${pattern}`)
const buildPatternPairs = pattern => pipe(
  split("\n"),
  map(replace("| ", "")),
  map(trim),
  map(split(" = "))
)(pattern)
const guard = args => pattern => buildPatternPairs(pattern).find(pair => buildPredicateFn(args, pair[0])())[1]

const result = guard({a,b,c})(`
  | a > b = 1337
  | b > c = 999
  | c > a = 42
  | c > b = 11
  | true = 'default value'
`)


console.log(result) // 42

@yamafaktory
Copy link
Owner

Thanks a lot for your work, I'm going to think about all of these implementations. I don't want to use Ramda (which is great) just for the benefit of the pipe function, it will increase the size of the module and I want to avoid any dependency. I also want to keep the nicety of the tagged template literal (not enclosed in parens). The last point, I don't think using a regex will make it run slower (pre-compiled regex are faster).

@edmulraney
Copy link
Author

Fair do's. Ramda was just for POC ;)
Out of curiosity is the tagged template for aesthetics or functionality?

@yamafaktory
Copy link
Owner

Definitely, for aesthetics, many libraries are going this way recently (can think of https://github.com/hyperapp/hyperapp#html for example).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants