https://github.com/unclechu/purescript-for-haskellers
Some info that supposed to help to understand PureScript from Haskell perspective
https://github.com/unclechu/purescript-for-haskellers
docs haskell purescript typed-language
Last synced: 29 days ago
JSON representation
Some info that supposed to help to understand PureScript from Haskell perspective
- Host: GitHub
- URL: https://github.com/unclechu/purescript-for-haskellers
- Owner: unclechu
- License: unlicense
- Created: 2018-02-22T13:48:07.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2018-08-22T12:40:40.000Z (over 6 years ago)
- Last Synced: 2025-03-18T15:54:51.101Z (about 1 month ago)
- Topics: docs, haskell, purescript, typed-language
- Homepage: http://www.purescript.org
- Size: 7.81 KB
- Stars: 32
- Watchers: 3
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# PureScript For Haskellers
Some info that supposed to help
to understand [PureScript](http://www.purescript.org/)
from [Haskell](https://www.haskell.org/) perspective.If you already know js it will be even simplier.
## About PureScript
PureScript written in Haskell but usually distributed as binaries via NPM.
It uses **Bower** instead of **NPM** because **Bower**
have flat dependencies and better dependency resolution.
This explained better here: http://harry.garrood.me/blog/purescript-why-bower/PureScript is **strict** by default!
### Useful links
- https://pursuit.purescript.org
(kinda like https://stackage.org for Haskell)
- http://try.purescript.org (online REPL)### Chatting
- #purescript on Freenode
[Matrix](https://matrix.org/)
bridge: https://riot.im/app/#/room/#freenode_#purescript:matrix.org
- https://gitter.im/purescript/purescript
[Matrix](https://matrix.org/)
bridge: https://riot.im/app/#/room/#gitter_purescript=2Fpurescript:matrix.org## From Haskell perspective
1. **About `Prelude`**:
PureScript acts like `{-# LANGUAGE NoImplicitPrelude #-}` in Haskell,
and `Prelude` also isn't distributed with PureScript compiler.You need to install dependency `purescript-prelude` and to import it:
```purescript
import Prelude
```2. **About `forall`**:
PureScript acts like `{-# LANGUAGE ExplicitForAll #-}` in Haskell.
You need to explicitly declare `forall` for every polymorphic type variable.
3. **About unicode**:
In PureScript using unicode is allowed by default.
Basic unicode symbols also included
(such as `∷`, `←`, `→`, `⇐`, `⇒`, `∀`, etc.)4. **Basic operators equivalents** (those which differ):
| PureScript | Haskell |
| --- | --- |
| `(<<<)` | `(.)` |
| `(>>>)` | `flip (.)` or `(.>)` from `flow` package |
| `(#)` | `(Data.Function.&)` from `base` package |
| `(<#>)` | `(Data.Functor.<&>)` from `base` package |
| `(<>)` (`Semigroup` type class) | `(++)` |
| `a *> b` (`Apply` type class) | `a >> b` |
| `b <* a` (`Apply` type class) | `b << a` |5. **Basic functions equivalents** (those which differ):
| PureScript | Haskell |
| --- | --- |
| `map` (`Functor` type class) | `fmap` (works like `map` for lists) |
| `unsafeThrow`
from `Control.Monad.Eff.Exception.Unsafe`
from `purescript-exceptions` package | `error` |
| `forkAff`
from `Control.Monad.Aff`
from `purescript-aff` package | `forkIO` |If you're looking for **Haskell**'s `Control.Concurrent.MVar` look at
**PureScript**'s `Control.Monad.Aff.AVar` from `purescript-aff` package.6. **About point-free style**:
For partially applied operators you must specify *ghost* place for a value:
| PureScript | Haskell |
| --- | --- |
| `(_ + 2)` | `(+ 2)` |
| `(2 + _)` | `(2 +)` |You're defenitely familiar with `{-# LANGUAGE LambdaCase #-}` in **Haskell**:
In **PureScript** you have kinda the same, but again,
you need to explicitly set *ghost* place for a value:```purescript
case _ of
Just x -> 34
Nothing -> 42
```That in **Haskell** would be:
```haskell
\case
Just x -> 34
Nothing -> 42
```To update a record in **PureScript** you also use a *ghost* place marker:
```purescript
_ { foo = 42 }
```But in **PureScript** you also able to easily modify nested records without
even using stuff like lenses:```purescript
_ { foo { bar { baz = 42 } } }
```You able create a function that fills record values this way:
```purescript
{ foo: _, bar: _ }
```Which is equivalent to:
```purescript
\foo bar -> { foo: foo, bar: bar }
```Or even to (as in js):
```purescript
\foo bar -> { foo, bar }
```7. **About Unit**:
| PureScript | Haskell |
| --- | --- |
| Type `Unit` | Type `()` |
| Value `unit` | Value `()` |8. **About IO**:
If you're looking what would be equivalent to `IO ()` in **Haskell** or just
wondering what the heck is `Eff (foo :: FOO) Unit`:**PureScript** have improved implementation of `IO` monad in **Haskell**, the
main difference is that `Eff` monad (in **PureScript**) have additional
parameter to specify limitation of possible side-effects (such as `CONSOLE`,
`DOM`, `REF`, etc.) so you can have more precise control of `IO` stuff.You defenitely should read official docs about this, the story couldn't be
told in few sentences.Few tips about **Eff** (*Eff* means *effects*):
- `IO ()` is kinda `forall eff. Eff eff Unit`;
- You must type your own `Eff` monads providing type of side-effects which it
going to make (e.g. `Eff (console :: CONSOLE) Unit`);
- But usually it's better to allow to use your monad inside more complex ones
by making it polymorphic (e.g.
`forall eff. Eff (console :: CONSOLE | eff)`, that means it can do
`CONSOLE` stuff but not limited to be used in context of others);
- `|` could be read as `as` (this aliases whole block inside parentheses).For async stuff (kinda threading, but remember you're in js world, it's not
really threads) you have similar `Aff` monad. You also should read docs about
this too.Few tips about **Aff**:
- Doing `Aff` is kinda doing `forkIO` in **Haskell** I believe;
- Use `launchAff` or `launchAff_` to run `Aff` from `Eff` monad
asynchronously;
- Use `forkAff` to run another `Aff` from `Aff` monad asynchronously;
- Use `liftEff` (`Control.Monad.Eff.Class` from `purescript-eff`)
to execute `Eff` from `Aff` monad;
- Use `liftEff'` (`Control.Monad.Aff` from `purescript-aff`)
to execute `Eff` from `Aff` monad if `Eff` monad has `EXCEPTION` effect.Keep in mind that **PureScript** is strict by default, so using:
```purescript
if condition
then someMonad foo bar
else pure unit
```could be better than:
```purescript
when condition $ someMonad foo bar
```in sense of efficiency, because `if` condition compiles to native js `if`
condition while `when` constructs function reference with possible partial
application.See also:
- https://pursuit.purescript.org/packages/purescript-eff
- https://pursuit.purescript.org/packages/purescript-aff9. **About booleans**
| PureScript | Haskell |
| --- | --- |
| Type `Boolean` | Type `Bool` |
| Value `true` | Value `True` |
| Value `false` | Value `False` |10. **About tuples**
In **PureScript** there's no special syntax for tuples.
You also need to install `purescript-tuples`.
| PureScript | Haskell |
| --- | --- |
| Type `Tuple Bool Int` | Type `(Bool, Int)` |
| Value `Tuple true 42` | Value `(True, 42)` |
| Pattern `(Tuple x y)` | Pattern `(x, y)` |11. **About lists**
**PureScript** has builtin `Array`s.
Functional `List`s are provided by `purescript-lists` package.`[1,2,3]` will produce an `Array Int`
(not `[Int]` because in **PureScript**
there's no sugar for typing `Array`s/`List`s).**PureScript** doesn't have special syntax for `Array` comprehensions.
Here is an example of doing comprehension using monads:```purescript
factors :: Int -> Array (Tuple Int Int)
factors n = do
a <- 1 .. n
b <- 1 .. a
guard $ a * b == n
pure $ Tuple a b
```An example of `Array` patterns:
```purescript
f [] = -1
f [x] = x
f [x, y] = x * y
f _ = 0
```There's no builtin *cons* for `Array`s for pattern-matching
(some performance issues)
but some helpers are provided by `purescript-arrays` package.See also about this:
https://stackoverflow.com/questions/42450347/purescript-pattern-match-arrays-of-unknown-length#42450443Pattern-matching on `List`s:
| PureScript | Haskell |
| --- | --- |
| `(Cons x xs)` | `(x : xs)` |12. **About records**:
Records in **PureScript** isn't limited to be used in context of `data`,
they're independent, you don't need (but may) have a wrapper for a record.Here is an example of a function that works with records:
```purescript
foo :: { foo :: String, bar :: Int } -> Int
foo x = x.bar
```Type of `foo` is equivalent to:
```purescript
foo :: Record (foo :: String, bar :: Int) -> Int
````foo` also can deal with any record that have `bar :: Int`
if it's typed like this:```purescript
foo :: forall r. { bar :: Int | r } -> Int
```You can read about `|` above, it acts here the same way.
Constructing new records is simple:
```purescript
bar = { foo: "Foo", bar: 42, baz: true }
```But keep in mind that when you construct new record you use `:` but when you
update a record you use `=`:```purescript
bar { bar = 34 }
```An example how to update a nested record:
```purescript
foo { bar { baz { bzz = 42 } } }
```Destructuring also works as in js:
1.
```purescript
foo x = log x.bar
```
```purescript
foo { bar } = <- log bar
```
```purescript
foo { bar: baz } = <- log baz
```
2.
```purescript
foo = do
x <- bar
log x.baz
```
```purescript
foo = do
{ baz } <- bar
log baz
```
```purescript
foo = do
{ baz: bzz } <- bar
log bzz
```13. **About deriving type class instance**:
Deriving instances separated from `data`, here's an example:
```purescript
derive instance eqLocation :: Eq Location
derive instance genericLocation :: Generic Location
instance showLocation :: Show Location where show = gShow
```Names `eqLocation`, `genericLocation` and `showLocation` is just for
produced js code, they're named like this just by convention but they can be
named differently.14. **About imports**:
In **PureScript** you don't have `qualified` keyword for imports,
if an import have `as` alias it **is** `qualified`.In **PureScript** `as` keyword must be places after everything
(even after explicit imports).| PureScript | Haskell |
| --- | --- |
| `import Data.Foo as Foo` | `import qualified Data.Foo as Foo` |
| `import Data.Foo as Foo (foo)` | `import qualified Data.Foo (foo) as Foo` |15. **About some packages**:
- `Maybe` isn't included, install `purescript-maybe`
- `purescript-console` for writing to the console
- `purescript-nullable` to deal with js `null`s (when you really need it)
- `purescript-generics` to deal with `Generic` stuff
- `purescript-lens` if you're looking for Kmett's lensesThis is pretty short list that supposed to get basic stuff as fast as possible,
read articles by this links to go deeper:- https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md
- https://github.com/purescript/documentation/blob/master/guides/Getting-Started.md
- https://github.com/purescript/documentation/tree/master/language