Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dramforever/each
https://github.com/dramforever/each
haskell
Last synced: 17 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/dramforever/each
- Owner: dramforever
- License: bsd-3-clause
- Created: 2017-02-05T14:24:44.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2019-12-06T20:00:08.000Z (almost 5 years ago)
- Last Synced: 2024-10-03T18:37:25.508Z (about 1 month ago)
- Topics: haskell
- Language: Haskell
- Size: 13.7 KB
- Stars: 10
- Watchers: 6
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# each
[![Hackage](https://img.shields.io/hackage/v/each)](https://hackage.haskell.org/package/each)
Inspired by [the Scala library of the same name](https://github.com/ThoughtWorksInc/each),
each is a Template Haskell library that transforms expressions containing
invocations of impure subexpressions into do-notation. Just mark your impure
subexpressions with `bind` or `~!` and they will be called appropriately,
as in this small demo:ghci> :m Each
ghci> $(each [| "Hello, " ++ (~! getLine) |])
World <--[keyboard input]
"Hello, World"With the `ApplicativeDo` GHC extension, calls to `fmap` and `<*>` will be
arranged so that you don't need to worry if you use, say, Haxl and needs
`Applicative` for parallelism.Most constructs where this would make things much more simpler are already
supported. In particular, these are okay:- Nested `bind`s.
- Branching constructs, even if the branches themselves uses `bind`. The
generated `do`-notation will generally match imperative intuition.These are some quirks:
- `let` expressions are evaluated sequentially. `each` currently lacks support
for detecting pure `let` expressions.
- `where` is not implemented.
- Parameters to lambda functions may not be used impurely. This is acceptable,
but the error message may be confusing:ghci> :m Each
ghci> $(each [| (\x -> bind x) |]):25:3: error:
• The exact Name ‘x_acBv’ is not in scope
Probable cause: you used a unique Template Haskell name (NameU),
perhaps via newName, but did not bind it
If that's it, then -ddump-splices might be useful
• In the untyped splice: $(each [| (\ x -> bind x) |])Also, `bind`s in the lambda will be run when the lambda is *constructed*,
not when it's called.
- `PatternGuard`, `LambdaCase` and a few other extensions (uncertain) are not
yet implemented.If you find something wrong, or really want some feature, feel free to leave an
issue.## How it works
The basic structure of an `each` block is this:
```haskell
$(each [| ... |])
```Inside of this block, three (interchangable) ways are used to mark impure
subexpressions:- `bind expr`
- `bind $ expr`
- `(~! expr)``do`-notation is generated according to left-to-right order, and branching is
handled.## More demos
A more detailed demo:
ghci> :m Each
ghci> :{
| $(each [|
| "Hey it works"
| ++ show (length $
| "something"
| ++ (~! readFile "/etc/issue")
| ++ (~! readFile "/etc/issue.net"))
| |])
| :}
"Hey it works64"Nested binds also work as expected.
ghci> :m Each
ghci> prompt str = putStrLn str *> getLine
ghci> $(each [| "Nah just " ++ (~! prompt ("What's " ++ bind getLine ++ "?")) |])
something <--[keyboard input]
What's something?
nothing <--[keyboard input]
"Nah just nothing"