summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md85
-rw-r--r--examples/helper.js10
-rw-r--r--lambda2js.cabal84
-rw-r--r--src/Parser.hs9
-rw-r--r--src/lambda2js.hs12
5 files changed, 169 insertions, 31 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..636468f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,85 @@
+Welcome to lambda2js
+====================
+
+Before you get any further: lambda2js is mainly a fun project.
+So if you are not in the mood simply leave as it is not for you.
+
+If you need something serious, try [PureScript](http://www.purescript.org/),
+[Haste](http://haste-lang.org/), [elm](http://elm-lang.org/),
+or [Fay](https://github.com/faylang/fay/wiki).
+
+As you can guess just by looking at the name, lambda2js is compiler
+that takes simple syntactically sugared untyped lambda calculus and produces
+JavaScript code. Though this project is meant as fun, it actually works.
+
+Lambda2js is open source (licensed under GPL-3) and patches are welcome.
+
+Motivation
+----------
+
+Have you ever found yourselves writing JavaScript code and thinking:
+"Oh my... How nice would it be to have this function with flipped arguments.
+And now I have to write wrapper function, or at least some anonymous function
+that will do what I need. In functional language I would simply use
+`flip` and that would be it!" Well, now it is your time as lambda2js
+was brought to light.
+
+Example
+-------
+
+In examples you can find [simple example](examples/example.ulc),
+that will get compiled into
+
+~~~ { .javascript }
+K = function(x){return function(y){return x}}
+S = function(f){return function(g){return function(x){return f(x)(g(x))}}}
+I = S(K)(K)
+Dot = function(f){return function(g){return function(x){return f(g(x))}}}
+Flip = function(f){return function(x){return function(y){return f(y)(x)}}}
+True = K
+Not = Flip
+False = Not(True)
+If = I
+Zero = function(s){return function(z){return z}}
+Succ = function(n){return function(s){return function(z){return n(s)(s(z))}}}
+IsZero = function(n){return n(K(False))(True)}
+Add = function(m){return function(n){return function(s){return function(z){return m(s)(n(s)(z))}}}}
+Mul = function(m){return function(n){return function(s){return function(z){return m(n(s))(z)}}}}
+Pow = function(m){return function(n){return function(s){return function(z){return n(m)(s)(z)}}}}
+One = Succ(Zero)
+Two = Succ(One)
+Three = Succ(Two)
+Tup = function(x){return function(y){return function(p){return p(x)(y)}}}
+Fst = function(t){return t(K)}
+Snd = function(t){return t(Flip(K))}
+Fac = function(n){return Snd(n(function(t){return t(function(x){return function(y){return Tup(Succ(x))(Mul(x)(y))}})})(Tup(One)(One)))}
+~~~~
+
+which is fully functional (pun intended) JavaScript. It can be played with:
+combined with small [helper library for seamless integration](examples/helper.js),
+one can compute `(2+3)!`.
+
+~~~ { .javascript }
+alert(funToInt(Fac(Add(Two)(Three))))
+~~~
+
+Flipping arguments can be as simple as
+
+~~~ { .javascript }
+alert(uncurry2(Flip(curry2(Math.pow)))(2,3))
+~~~
+
+...and much more.
+
+Origin
+------
+
+I was playing with JavaScript the other day, pondering higher functions.
+Trying the usual stuff like [Church numerals](http://en.wikipedia.org/wiki/Church_encoding)
+and other. I found myself under avalanche of JavaScript
+boilerplate. Just compare `function(x){return x}` and `\ x . x`.
+
+And then it occurred to me: this can be easily automated! I can
+write code I like and get code I need. So I sat down to my console
+and in just couple of moments I came up with 10 commandm\^W\^Wthis little
+project. Enjoy.
diff --git a/examples/helper.js b/examples/helper.js
new file mode 100644
index 0000000..2e6b77b
--- /dev/null
+++ b/examples/helper.js
@@ -0,0 +1,10 @@
+sc = function(x){return x+1}
+funToInt = function(n){return n(sc)(0)}
+funToBool = function(b){return b(true)(false)}
+
+curry2 = function(f){return function(x){return function (y){return f(x,y)}}}
+curry3 = function(f){return function(x){return function (y){return function(z){f(x,y,z)}}}}
+curry4 = function(f){return function(w){return function(x){return function(y){return function(z){return f(w,x,y,z)}}}}}
+uncurry2 = function(f){return function(x,y){return f(x)(y)}}
+uncurry3 = function(f){return function(x,y,z){return f(x)(y)(z)}}
+uncurry4 = function(f){return function(w,x,y,z){return f(w)(x)(y)(z)}}
diff --git a/lambda2js.cabal b/lambda2js.cabal
index 05dbc8b..b0ee992 100644
--- a/lambda2js.cabal
+++ b/lambda2js.cabal
@@ -1,31 +1,73 @@
-Name: lambda2js
-Version: 0.1
-Synopsis: Untyped Lambda calculus to JavaScript compiler
-Description: Simple though savage untyped Lambda calculus to JavaScript compiler.
- I hope you will have same fun playing with it as I had writing it.
-Homepage: https://patch-tag.com/r/mkollar/lambda2js/
-Stability: experimental
-License: GPL-3
-License-file: LICENSE
-Author: Matej Kollar <208115@mail.muni.cz>
-Maintainer: Matej Kollar <208115@mail.muni.cz>
+-- Initial lambda2js.cabal generated by cabal init. For further
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name: lambda2js
+
+-- The package version. See the Haskell package versioning policy (PVP)
+-- for standards guiding when and how versions should be incremented.
+-- http://www.haskell.org/haskellwiki/Package_versioning_policy
+-- PVP summary: +-+------- breaking API changes
+-- | | +----- non-breaking API additions
+-- | | | +--- code changes with no API change
+version: 0.1.0.1
+
+-- A short (one-line) description of the package.
+synopsis: Untyped Lambda calculus to JavaScript compiler
+
+-- A longer description of the package.
+description: Simple though savage untyped Lambda calculus to JavaScript compiler.
+ I hope you will have same fun playing with it as I had writing it.
+
+homepage: https://github.com/xkollar/lambda2js
+stability: experimental
+
+-- The license under which the package is released.
+license: GPL-3
+
+-- The file containing the license text.
+license-file: LICENSE
+
+-- The package author(s).
+author: Matej Kollar <208115@mail.muni.cz>
+
+
+-- An email address to which users can send suggestions, bug reports, and
+-- patches.
+maintainer: 208115@mail.muni.cz
-- A copyright notice.
-- Copyright:
-Category: Compiler
+category: Compiler
+
+build-type: Simple
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version: >= 1.6
+
+extra-source-files: README.md
+ examples/*.js
+ examples/*.ulc
-Build-type: Simple
+executable lambda2js
+ main-is: lambda2js.hs
-Extra-source-files: examples/example.ulc
+ -- Modules included in this executable, other than Main.
+ other-modules: Parser, Types
-Cabal-version: >= 1.4
+ -- Other library packages from which modules are imported.
+ build-depends: base >=4.5 && <4.8, parsec >=3
+ -- Directories containing source files.
+ hs-source-dirs: src
+ ghc-options: -Wall -fno-warn-unused-do-bind
-Executable lambda2js
- Main-is: lambda2js.hs
- Build-depends: haskell2010,
- parsec >= 3
- Hs-source-dirs: src
- Other-modules: Parser, Types
+source-repository head
+ type: git
+ location: https://github.com/xkollar/lambda2js.git
+source-repository this
+ type: git
+ location: https://github.com/xkollar/lambda2js.git
+ tag: lambda2js-0.1.0.1
diff --git a/src/Parser.hs b/src/Parser.hs
index a8e21a6..da58ed2 100644
--- a/src/Parser.hs
+++ b/src/Parser.hs
@@ -1,9 +1,10 @@
-module Parser ( source ) where
-
-import Types
+module Parser (source) where
+import Control.Monad (void)
import Text.ParserCombinators.Parsec
+import Types
+
ndSepBy1 :: GenParser a b c -> GenParser a b d -> GenParser a b [c]
ndSepBy1 p sep = do
x <- p
@@ -19,7 +20,7 @@ mySpace :: Parser Char
mySpace = char ' '
mySpaces :: Parser ()
-mySpaces = many1 mySpace >> return ()
+mySpaces = void $ many1 mySpace
source :: Parser Source
source = do
diff --git a/src/lambda2js.hs b/src/lambda2js.hs
index 3d44688..6d193b1 100644
--- a/src/lambda2js.hs
+++ b/src/lambda2js.hs
@@ -1,11 +1,11 @@
-module Main ( main ) where
+module Main (main) where
-import Types
-import Parser ( source )
+import System.Environment (getArgs)
+import System.IO (Handle, hPutStr, stderr, stdout)
+import Text.ParserCombinators.Parsec (parse)
-import System.Environment ( getArgs )
-import System.IO ( stdout , stderr , hPutStr , Handle )
-import Text.ParserCombinators.Parsec ( parse )
+import Types
+import Parser (source)
main :: IO ()
main = do