-
Notifications
You must be signed in to change notification settings - Fork 89
Home
A proper subset of Haskell that compiles to JavaScript.
Fay has the following properties:
- A proper syntactic and semantic subset of Haskell
- Statically typed
- Lazy
- Pure by default
- Compiles to JavaScript
- Has fundamental data types (Double, String, etc.) based upon what JS can support, and compound data types (ADTs and GADTs)
- Outputs minifier-aware code for small compressed size
- Has a trivial foreign function interface to JavaScript
- Supports cabal installation of Fay packages
- Can automatically transcode values to/from JSON using the FFI
- Provides an API to transcode on the server side as well
- Lets you call Fay code from JavaScript
- Has the
Fay
monad for side effects (think of it likeIO
)
Install Fay from hackage
cabal install cpphs
# make sure cpphs is in your PATH
cabal install fay fay-base
Write awesome software
{-# LANGUAGE EmptyDataDecls #-}
module Hello where
import FFI
data Event
alert :: String -> Fay ()
alert = ffi "alert(%1)"
setBodyHtml :: String -> Fay ()
setBodyHtml = ffi "document.body.innerHTML = %1"
addWindowEvent :: String -> (Event -> Fay ()) -> Fay ()
addWindowEvent = ffi "window.addEventListener(%1, %2)"
greet :: Event -> Fay ()
greet event = do
putStrLn "The document has loaded"
setBodyHtml "Hello HTML!"
main :: Fay ()
main = do
putStrLn "Hello Console!"
alert "Hello Alert!"
addWindowEvent "load" greet
Compile it
fay Hello.hs --html-wrapper
--html-wrapper
generates Hello.html
that includes the compiled JavaScript.
open Hello.html
- Installing and running (including sandbox instructions)
- Troubleshooting
- Contributing to Fay
- Package management with Cabal
- Changelog
- Calling Fay from JavaScript
- Foreign Function Interface
- What is not supported?
- Using fay-text/OverloadedStrings
- Why Fay does not currently support type-classes
- Fay Status Update September 2013: ZuriHac, typeclasses, haskell suite, and strictness wrappers
- Generated code
- Reducing output size
- Compiler passes
- Package Versioning Policy
- Wish list (project suggestions)
- File an issue on github
- IRC: #fay @ irc.freenode.net
- Twitter: @FayHaskell
- The Fay tag on StackOverflow
- Calcudoku Solver/Tutorial
- Yesod Blog: Yesod, AngularJS and Fay
- Happstack Blog: Happstack, Fay, & Acid-State: Shared Datatypes are Awesome
- Fun with Fay - A Ring Oscillator
- CodeWorld and the Future
- A Fay IDE written in Fay (needs an update for recent fay versions)
- Fay (JavaScript/Haskell) on Code Deconstructed Part 1 Part 2. In depth videos on the compiler's internals
- 24 Days of Hackage: fay: Nice introductory tutorial by ocharles
- happstack-fay: Fay integration for Happstack hackage
- snaplet-fay: Fay integration for Snap github, hackage
- yesod-fay: Fay integration for Yesod github, hackage
- fay-jquery: JQuery bindings github, hackage
- fay-text: Data.Text interface represented by JavaScript strings github, hackage
- fay-uri: FFI wrapper for jsUri, github, hackage
- circle-packing: Given a number of circles with their radii, this package tries to arrange them tightly, without overlap and forming a large circle. Works with Fay, GHC, and Haste fay demo, hackage
- fay-ref: Like IORef but for Fay github, hackage
- cinder: Markup (HTML and SVG) and DOM manipulation DSL website, github
The JavaScript problem is two-fold and can be described thus:
- JavaScript sucks: The depths to which JavaScript sucks is well-documented and well-understood. Its main faults are: its lack of module system, weak-typing, verbose function syntax, late binding, which has led to the creation of various static analysis tools to alleviate this language flaw, but with limited success (there is even a static type checker), finicky equality/automatic conversion, this behaviour, and lack of static types.
- We need JavaScript: Using it for what it is good for, i.e. providing a platform for browser development, but not using the language per se, is therefore desirable, and many are working to achieve this, in varying forms. There are various ways to do it, but we ought to opt for compiling an existing language, Haskell, to JavaScript, because we do not have time to learn or teach other people a new language, garner a new library set and a new type checker and all that Haskell implementations provide.
CoffeeScript is a syntactic layer above JavaScript that does not change semantics. It adds some additional syntactic constructs, but makes no fundamental changes, you are still essentially working in JavaScript, but with more convenient syntactic features.
Fay on the other hand is a different language to JavaScript entirely, with a different semantics. It is lazy, it has partial application and currying, pattern matching for all data types, all expressions are pure and only statements in the Fay monad can be impure.
LiveScript is also a similar approach in the wave of compile-to-JS projects that have developed in recent years. LiveScript's translation is also quite readable and predictable, this is also the only thing in common with Fay.
TypeScript is another superset of JavaScript. TypeScript adds syntactic sugar for classes and lambdas, and static typing with type inference. TypeScript can be a good choice when you have a large JS code base and you can't afford to migrate it to a new language, or if you are in a team that doesn't want to switch to a new language but still want to have some static guarantees. The type system is at the moment fairly limited with generics just recently being introduced. One problem is the existence of an any
type which can propagate throughout your program, it's easy to write obviously incorrect programs that still typecheck and fail at runtime.
GHCJS aims to support as much of GHC as possible. This gives you STM, concurrency, and the ability to compile large portions of Hackage. Fay's approach is to stay close to JavaScript by supporting the available types, sticking to the single threaded runtime, producing small output, and making it easy to interoperate with JS libraries and applications. A potential problem with compiling GHC packages in that the dependencies easily get out of hand. When compiling to a binary this usually doesn't matter, but on the web just a couple of megabytes can be too much to serve to users. Fay is also a much smaller compiler, and the generated output is easier to read which makes it easier to debug your own code and contribute to the compiler itself.
For more comments see this reddit thread
Roy is an approach to bring functional programming to JavaScript, it has lots of interesting features but it has different syntax and type-system semantics to Haskell.
Elm, equally, is an approach to bringing functional programming to the web, and is less generic than Roy, as it specifically focuses on web programming. It, too, borrows from Haskell and looks a bit like it, but is (consciously) different in syntax and semantics.
Idris is a strictly evaluated dependently typed language with Haskell like syntax.
All of these languages are very interesting and promising approaches. What Fay offers is to keep the existing compiler, GHC, for its battle-tested type checking and code analysis, and to use existing parsers for Haskell to support a subset of its syntax. This way, one does not have to replace the tooling infrastructure and workflow that one is used to. With the exception of actions in the Fay monad, pure functions can be type checked and run within GHCi.
Additionally, because all Fay code is Haskell code, certain modules can be shared between the ‘native’ Haskell and ‘web’ Haskell, most interestingly the types module of your project. This enables two things:
The enforced (by GHC) coherence of client-side and server-side data types. The transparent serializing and deserializing of data types between these two entities (e.g. over AJAX).