{"id":16345397,"url":"https://github.com/unclechu/purescript-for-haskellers","last_synced_at":"2025-03-23T00:32:43.544Z","repository":{"id":66007010,"uuid":"122484540","full_name":"unclechu/purescript-for-haskellers","owner":"unclechu","description":"Some info that supposed to help to understand PureScript from Haskell perspective","archived":false,"fork":false,"pushed_at":"2018-08-22T12:40:40.000Z","size":8,"stargazers_count":32,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-18T15:54:51.101Z","etag":null,"topics":["docs","haskell","purescript","typed-language"],"latest_commit_sha":null,"homepage":"http://www.purescript.org","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unclechu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-22T13:48:07.000Z","updated_at":"2021-12-18T07:42:09.000Z","dependencies_parsed_at":"2023-04-30T11:48:17.248Z","dependency_job_id":null,"html_url":"https://github.com/unclechu/purescript-for-haskellers","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unclechu%2Fpurescript-for-haskellers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unclechu%2Fpurescript-for-haskellers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unclechu%2Fpurescript-for-haskellers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unclechu%2Fpurescript-for-haskellers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unclechu","download_url":"https://codeload.github.com/unclechu/purescript-for-haskellers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245040235,"owners_count":20551297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docs","haskell","purescript","typed-language"],"created_at":"2024-10-11T00:31:28.253Z","updated_at":"2025-03-23T00:32:43.526Z","avatar_url":"https://github.com/unclechu.png","language":null,"readme":"# PureScript For Haskellers\n\nSome info that supposed to help\nto understand [PureScript](http://www.purescript.org/)\nfrom [Haskell](https://www.haskell.org/) perspective.\n\nIf you already know js it will be even simplier.\n\n## About PureScript\n\nPureScript written in Haskell but usually distributed as binaries via NPM.\n\nIt uses **Bower** instead of **NPM** because **Bower**\nhave flat dependencies and better dependency resolution.\u003cbr\u003e\nThis explained better here: http://harry.garrood.me/blog/purescript-why-bower/\n\nPureScript is **strict** by default!\n\n### Useful links\n\n- https://pursuit.purescript.org\n  (kinda like https://stackage.org for Haskell)\n- http://try.purescript.org (online REPL)\n\n### Chatting\n\n- #purescript on Freenode\u003cbr\u003e\n  [Matrix](https://matrix.org/)\n  bridge: https://riot.im/app/#/room/#freenode_#purescript:matrix.org\n- https://gitter.im/purescript/purescript\u003cbr\u003e\n  [Matrix](https://matrix.org/)\n  bridge: https://riot.im/app/#/room/#gitter_purescript=2Fpurescript:matrix.org\n\n## From Haskell perspective\n\n1. **About `Prelude`**:\n\n   PureScript acts like `{-# LANGUAGE NoImplicitPrelude #-}` in Haskell,\n   and `Prelude` also isn't distributed with PureScript compiler.\n\n   You need to install dependency `purescript-prelude` and to import it:\n\n   ```purescript\n   import Prelude\n   ```\n\n2. **About `forall`**:\n\n   PureScript acts like `{-# LANGUAGE ExplicitForAll #-}` in Haskell.\n\n   You need to explicitly declare `forall` for every polymorphic type variable.\n\n3. **About unicode**:\n\n   In PureScript using unicode is allowed by default.\n\n   Basic unicode symbols also included\n   (such as `∷`, `←`, `→`, `⇐`, `⇒`, `∀`, etc.)\n\n4. **Basic operators equivalents** (those which differ):\n\n   | PureScript                      | Haskell                                  |\n   | ---                             | ---                                      |\n   | `(\u003c\u003c\u003c)`                         | `(.)`                                    |\n   | `(\u003e\u003e\u003e)`                         | `flip (.)` or `(.\u003e)` from `flow` package |\n   | `(#)`                           | `(Data.Function.\u0026)` from `base` package  |\n   | `(\u003c#\u003e)`                         | `(Data.Functor.\u003c\u0026\u003e)` from `base` package |\n   | `(\u003c\u003e)` (`Semigroup` type class) | `(++)`                                   |\n   | `a *\u003e b` (`Apply` type class)   | `a \u003e\u003e b`                                 |\n   | `b \u003c* a` (`Apply` type class)   | `b \u003c\u003c a`                                 |\n\n5. **Basic functions equivalents** (those which differ):\n\n   | PureScript                                                                                         | Haskell                             |\n   | ---                                                                                                | ---                                 |\n   | `map` (`Functor` type class)                                                                       | `fmap` (works like `map` for lists) |\n   | `unsafeThrow`\u003cbr\u003efrom `Control.Monad.Eff.Exception.Unsafe`\u003cbr\u003efrom `purescript-exceptions` package | `error`                             |\n   | `forkAff`\u003cbr\u003efrom `Control.Monad.Aff`\u003cbr\u003efrom `purescript-aff` package                             | `forkIO`                            |\n\n   If you're looking for **Haskell**'s `Control.Concurrent.MVar` look at\n   **PureScript**'s `Control.Monad.Aff.AVar` from `purescript-aff` package.\n\n6. **About point-free style**:\n\n   For partially applied operators you must specify *ghost* place for a value:\n\n   | PureScript | Haskell |\n   | ---        | ---     |\n   | `(_ + 2)`  | `(+ 2)` |\n   | `(2 + _)`  | `(2 +)` |\n\n   You're defenitely familiar with `{-# LANGUAGE LambdaCase #-}` in **Haskell**:\n\n   In **PureScript** you have kinda the same, but again,\n   you need to explicitly set *ghost* place for a value:\n\n   ```purescript\n   case _ of\n     Just x  -\u003e 34\n     Nothing -\u003e 42\n   ```\n\n   That in **Haskell** would be:\n\n   ```haskell\n   \\case\n     Just x  -\u003e 34\n     Nothing -\u003e 42\n   ```\n\n   To update a record in **PureScript** you also use a *ghost* place marker:\n\n   ```purescript\n   _ { foo = 42 }\n   ```\n\n   But in **PureScript** you also able to easily modify nested records without\n   even using stuff like lenses:\n\n   ```purescript\n   _ { foo { bar { baz = 42 } } }\n   ```\n\n   You able create a function that fills record values this way:\n\n   ```purescript\n   { foo: _, bar: _ }\n   ```\n\n   Which is equivalent to:\n\n   ```purescript\n   \\foo bar -\u003e { foo: foo, bar: bar }\n   ```\n\n   Or even to (as in js):\n\n   ```purescript\n   \\foo bar -\u003e { foo, bar }\n   ```\n\n7. **About Unit**:\n\n   | PureScript   | Haskell    |\n   | ---          | ---        |\n   | Type `Unit`  | Type `()`  |\n   | Value `unit` | Value `()` |\n\n8. **About IO**:\n\n   If you're looking what would be equivalent to `IO ()` in **Haskell** or just\n   wondering what the heck is `Eff (foo :: FOO) Unit`:\n\n   **PureScript** have improved implementation of `IO` monad in **Haskell**, the\n   main difference is that `Eff` monad (in **PureScript**) have additional\n   parameter to specify limitation of possible side-effects (such as `CONSOLE`,\n   `DOM`, `REF`, etc.) so you can have more precise control of `IO` stuff.\n\n   You defenitely should read official docs about this, the story couldn't be\n   told in few sentences.\n\n   Few tips about **Eff** (*Eff* means *effects*):\n\n   - `IO ()` is kinda `forall eff. Eff eff Unit`;\n   - You must type your own `Eff` monads providing type of side-effects which it\n     going to make (e.g. `Eff (console :: CONSOLE) Unit`);\n   - But usually it's better to allow to use your monad inside more complex ones\n     by making it polymorphic (e.g.\n     `forall eff. Eff (console :: CONSOLE | eff)`, that means it can do\n     `CONSOLE` stuff but not limited to be used in context of others);\n   - `|` could be read as `as` (this aliases whole block inside parentheses).\n\n   For async stuff (kinda threading, but remember you're in js world, it's not\n   really threads) you have similar `Aff` monad. You also should read docs about\n   this too.\n\n   Few tips about **Aff**:\n\n   - Doing `Aff` is kinda doing `forkIO` in **Haskell** I believe;\n   - Use `launchAff` or `launchAff_` to run `Aff` from `Eff` monad\n     asynchronously;\n   - Use `forkAff` to run another `Aff` from `Aff` monad asynchronously;\n   - Use `liftEff` (`Control.Monad.Eff.Class` from `purescript-eff`)\n     to execute `Eff` from `Aff` monad;\n   - Use `liftEff'` (`Control.Monad.Aff` from `purescript-aff`)\n     to execute `Eff` from `Aff` monad if `Eff` monad has `EXCEPTION` effect.\n\n   Keep in mind that **PureScript** is strict by default, so using:\n\n   ```purescript\n   if condition\n      then someMonad foo bar\n      else pure unit\n   ```\n\n   could be better than:\n\n   ```purescript\n   when condition $ someMonad foo bar\n   ```\n\n   in sense of efficiency, because `if` condition compiles to native js `if`\n   condition while `when` constructs function reference with possible partial\n   application.\n\n   See also:\n   - https://pursuit.purescript.org/packages/purescript-eff\n   - https://pursuit.purescript.org/packages/purescript-aff\n\n9. **About booleans**\n\n    | PureScript     | Haskell       |\n    | ---            | ---           |\n    | Type `Boolean` | Type `Bool`   |\n    | Value `true`   | Value `True`  |\n    | Value `false`  | Value `False` |\n\n10. **About tuples**\n\n    In **PureScript** there's no special syntax for tuples.\n\n    You also need to install `purescript-tuples`.\n\n    | PureScript            | Haskell            |\n    | ---                   | ---                |\n    | Type `Tuple Bool Int` | Type `(Bool, Int)` |\n    | Value `Tuple true 42` | Value `(True, 42)` |\n    | Pattern `(Tuple x y)` | Pattern `(x, y)`   |\n\n11. **About lists**\n\n    **PureScript** has builtin `Array`s.\n    Functional `List`s are provided by `purescript-lists` package.\n\n    `[1,2,3]` will produce an `Array Int`\n    (not `[Int]` because in **PureScript**\n    there's no sugar for typing `Array`s/`List`s).\n\n    **PureScript** doesn't have special syntax for `Array` comprehensions.\u003cbr\u003e\n    Here is an example of doing comprehension using monads:\n\n    ```purescript\n    factors :: Int -\u003e Array (Tuple Int Int)\n    factors n = do\n      a \u003c- 1 .. n\n      b \u003c- 1 .. a\n      guard $ a * b == n\n      pure $ Tuple a b\n    ```\n\n    An example of `Array` patterns:\n\n    ```purescript\n    f []     = -1\n    f [x]    = x\n    f [x, y] = x * y\n    f _      = 0\n    ```\n\n    There's no builtin *cons* for `Array`s for pattern-matching\n    (some performance issues)\n    but some helpers are provided by `purescript-arrays` package.\n\n    See also about this:\u003cbr\u003e\n    https://stackoverflow.com/questions/42450347/purescript-pattern-match-arrays-of-unknown-length#42450443\n\n    Pattern-matching on `List`s:\n\n    | PureScript    | Haskell    |\n    | ---           | ---        |\n    | `(Cons x xs)` | `(x : xs)` |\n\n12. **About records**:\n\n    Records in **PureScript** isn't limited to be used in context of `data`,\n    they're independent, you don't need (but may) have a wrapper for a record.\n\n    Here is an example of a function that works with records:\n\n    ```purescript\n    foo :: { foo :: String, bar :: Int } -\u003e Int\n    foo x = x.bar\n    ```\n\n    Type of `foo` is equivalent to:\n\n    ```purescript\n    foo :: Record (foo :: String, bar :: Int) -\u003e Int\n    ```\n\n    `foo` also can deal with any record that have `bar :: Int`\n    if it's typed like this:\n\n    ```purescript\n    foo :: forall r. { bar :: Int | r } -\u003e Int\n    ```\n\n    You can read about `|` above, it acts here the same way.\n\n    Constructing new records is simple:\n\n    ```purescript\n    bar = { foo: \"Foo\", bar: 42, baz: true }\n    ```\n\n    But keep in mind that when you construct new record you use `:` but when you\n    update a record you use `=`:\n\n    ```purescript\n    bar { bar = 34 }\n    ```\n\n    An example how to update a nested record:\n\n    ```purescript\n    foo { bar { baz { bzz = 42 } } }\n    ```\n\n    Destructuring also works as in js:\n\n    1.\n       ```purescript\n       foo x = log x.bar\n       ```\n       ```purescript\n       foo { bar } = \u003c- log bar\n       ```\n       ```purescript\n       foo { bar: baz } = \u003c- log baz\n       ```\n    2.\n       ```purescript\n       foo = do\n         x \u003c- bar\n         log x.baz\n       ```\n       ```purescript\n       foo = do\n         { baz } \u003c- bar\n         log baz\n       ```\n       ```purescript\n       foo = do\n         { baz: bzz } \u003c- bar\n         log bzz\n       ```\n\n13. **About deriving type class instance**:\n\n    Deriving instances separated from `data`, here's an example:\n\n    ```purescript\n    derive instance eqLocation :: Eq Location\n    derive instance genericLocation :: Generic Location\n    instance showLocation :: Show Location where show = gShow\n    ```\n\n    Names `eqLocation`, `genericLocation` and `showLocation` is just for\n    produced js code, they're named like this just by convention but they can be\n    named differently.\n\n14. **About imports**:\n\n    In **PureScript** you don't have `qualified` keyword for imports,\n    if an import have `as` alias it **is** `qualified`.\n\n    In **PureScript** `as` keyword must be places after everything\n    (even after explicit imports).\n\n    | PureScript                     | Haskell                                  |\n    | ---                            | ---                                      |\n    | `import Data.Foo as Foo`       | `import qualified Data.Foo as Foo`       |\n    | `import Data.Foo as Foo (foo)` | `import qualified Data.Foo (foo) as Foo` |\n\n15. **About some packages**:\n\n    - `Maybe` isn't included, install `purescript-maybe`\n    - `purescript-console` for writing to the console\n    - `purescript-nullable` to deal with js `null`s (when you really need it)\n    - `purescript-generics` to deal with `Generic` stuff\n    - `purescript-lens` if you're looking for Kmett's lenses\n\nThis is pretty short list that supposed to get basic stuff as fast as possible,\nread articles by this links to go deeper:\n\n- https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md\n- https://github.com/purescript/documentation/blob/master/guides/Getting-Started.md\n- https://github.com/purescript/documentation/tree/master/language\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funclechu%2Fpurescript-for-haskellers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funclechu%2Fpurescript-for-haskellers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funclechu%2Fpurescript-for-haskellers/lists"}