Merge branch 'master' into dev

This commit is contained in:
Evan Czaplicki 2013-10-28 11:27:07 +01:00
commit d8ced9ee74
22 changed files with 211 additions and 99 deletions

View file

@ -1,5 +1,5 @@
Name: Elm
Version: 0.9.0.2
Version: 0.10.0.2
Synopsis: The Elm language module.
Description: Elm aims to make client-side web-development more pleasant.
It is a statically/strongly typed, functional reactive
@ -88,7 +88,7 @@ Library
directory,
filepath,
indents,
language-ecmascript,
language-ecmascript < 1,
mtl >= 2,
pandoc >= 1.10,
parsec >= 3.1.1,
@ -157,7 +157,7 @@ Executable elm
directory,
filepath,
indents,
language-ecmascript,
language-ecmascript < 1,
mtl >= 2,
pandoc >= 1.10,
parsec >= 3.1.1,

View file

@ -3,8 +3,7 @@ Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/)
## Install
Download the [Haskell Platform 2012.2.0.0](http://hackage.haskell.org/platform/).
Elm definitely works with GHC 7.4, so newer versions of the Haskell Platform may work too.
Download the [Haskell Platform 2012.2.0.0 or later](http://hackage.haskell.org/platform/).
Once the Haskell Platform is installed:
cabal update
@ -39,10 +38,10 @@ commands place a simple program into `Main.elm`. Do this manually if you do not
have `printf`. The final command starts the Elm server at [localhost:8000](http://localhost:8000/),
allowing you to navigate to `Main.elm` and see your first program in action.
#### Wrap up
#### Final Notes
The `elm` package provides support for compilation of Elm code directly in Haskell and QuasiQuoting.
Check it out on Hackage if you are interested.
The `elm` package provides support for compilation of Elm code directly in Haskell.
Check it out [on Hackage](http://hackage.haskell.org/package/Elm) if you are interested.
If you are stuck, email [the list](https://groups.google.com/forum/?fromgroups#!forum/elm-discuss)
or ask a question in the [#Elm IRC channel](http://webchat.freenode.net/?channels=elm).

View file

@ -243,14 +243,17 @@ match :: (Show a) => a -> Case.Match () () -> State Int [Statement ()]
match span mtch =
case mtch of
Case.Match name clauses mtch' ->
do clauses' <- mapM (clause span name) clauses
do (isChars, clauses') <- unzip <$> mapM (clause span name) clauses
mtch'' <- match span mtch'
return (SwitchStmt () (access name) clauses' : mtch'')
return (SwitchStmt () (format isChars (access name)) clauses' : mtch'')
where
isLiteral p = case p of
Case.Clause (Right _) _ _ -> True
_ -> False
access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
format isChars e
| or isChars = InfixExpr () OpAdd e (string "")
| otherwise = e
Case.Fail ->
return [ ExprStmt () (obj "_E.Case" `call` [ref "$moduleName", string (show span)]) ]
@ -268,10 +271,13 @@ match span mtch =
_ -> dropEnd (acc ++ [m]) ms
clause span variable (Case.Clause value vars mtch) =
CaseClause () pattern <$> match span (Case.matchSubst (zip vars vars') mtch)
(,) isChar . CaseClause () pattern <$> match span (Case.matchSubst (zip vars vars') mtch)
where
vars' = map (\n -> variable ++ "._" ++ show n) [0..]
pattern = case value of
(isChar, pattern) =
case value of
Right (Chr c) -> (True, string [c])
_ -> (,) False $ case value of
Right (Boolean b) -> BoolLit () b
Right lit -> literal lit
Left name -> string $ case List.elemIndices '.' name of

View file

@ -25,16 +25,19 @@ tuple = do ts <- parens (commaSep expr)
record :: IParser T.Type
record =
do char '{' ; whitespace
ext <- extend
fs <- fields
(ext,fs) <- extended <|> normal
dumbWhitespace ; char '}'
return (T.Record fs ext)
where
extend = option T.EmptyRecord . try $ do
t <- tvar
whitespace >> string "|" >> whitespace
return t
fields = commaSep1 $ do
normal = (,) T.EmptyRecord <$> commaSep fields
-- extended record types require at least one field
extended = do
ext <- try (const <$> tvar <*> (whitespace >> string "|"))
whitespace
(,) ext <$> commaSep1 fields
fields = do
lbl <- rLabel
whitespace >> hasType >> whitespace
(,) lbl <$> expr

View file

@ -4,6 +4,8 @@ module SourceSyntax.Declaration where
import Data.Data
import qualified SourceSyntax.Expression as Expr
import SourceSyntax.Type
import SourceSyntax.PrettyPrint
import Text.PrettyPrint as P
data Declaration tipe var
= Definition (Expr.Def tipe var)
@ -23,3 +25,24 @@ instance Show Assoc where
L -> "left"
N -> "non"
R -> "right"
instance Pretty (Declaration t v) where
pretty decl =
case decl of
Definition def -> pretty def
Datatype tipe tvars ctors ->
P.hang (P.text "data" <+> P.text tipe <+> P.hsep (map P.text tvars)) 4
(P.sep $ zipWith join ("=" : repeat "|") ctors)
where
join c ctor = P.text c <+> prettyCtor ctor
prettyCtor (name, tipes) =
P.hang (P.text name) 2 (P.sep (map prettyParens tipes))
TypeAlias name tvars tipe ->
let alias = P.text name <+> P.hsep (map P.text tvars) in
P.hang (P.text "type" <+> alias <+> P.equals) 4 (pretty tipe)
-- TODO: actually write out the other cases. They are currently unused, but
-- this is probably going to be a bug someday.
_ -> P.text (show decl)

View file

@ -2,9 +2,11 @@ module Transform.Check (mistakes) where
import Transform.SortDefinitions (boundVars)
import SourceSyntax.Everything
import SourceSyntax.PrettyPrint
import qualified SourceSyntax.Type as T
import Data.List as List
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
import qualified Data.Set as Set
import Data.Data
import Data.Generics.Uniplate.Data
@ -13,7 +15,7 @@ import Text.PrettyPrint as P
mistakes :: (Data t, Data v) => [Declaration t v] -> [Doc]
mistakes decls =
map P.text $ concatMap findErrors (getLets decls)
illFormedTypes decls ++ map P.text (concatMap findErrors (getLets decls))
where
findErrors defs = duplicates defs ++ badOrder defs
@ -60,4 +62,46 @@ badOrder defs = go defs
_ -> []
illFormedTypes :: [Declaration t v] -> [Doc]
illFormedTypes decls = map report (Maybe.mapMaybe isIllFormed (aliases ++ adts))
where
aliases = [ (decl, tvars, [tipe]) | decl@(TypeAlias _ tvars tipe) <- decls ]
adts = [ (decl, tvars, concatMap snd ctors) | decl@(Datatype _ tvars ctors) <- decls ]
freeVars tipe =
case tipe of
T.Lambda t1 t2 -> Set.union (freeVars t1) (freeVars t2)
T.Var x -> Set.singleton x
T.Data _ ts -> Set.unions (map freeVars ts)
T.EmptyRecord -> Set.empty
T.Record fields ext -> Set.unions (freeVars ext : map (freeVars . snd) fields)
undeclared tvars tipes = Set.difference used declared
where
used = Set.unions (map freeVars tipes)
declared = Set.fromList tvars
isIllFormed (decl, tvars, tipes) =
let unbound = undeclared tvars tipes in
if Set.null unbound then Nothing
else Just (decl, Set.toList unbound)
report (decl, tvars) =
P.vcat [ P.text $ "Error: type variable" ++ listing ++ " unbound in:"
, P.text "\n"
, nest 4 (pretty decl) ]
where
listing =
case tvars of
[tvar] -> " " ++ quote tvar ++ " is"
_ -> "s" ++ addCommas (map ((++) " ") (addAnd (map quote tvars))) ++ " are"
addCommas xs
| length xs < 3 = concat xs
| otherwise = intercalate "," xs
addAnd xs
| length xs < 2 = xs
| otherwise = zipWith (++) (replicate (length xs - 1) "" ++ ["and "]) xs
quote tvar = "'" ++ tvar ++ "'"

View file

@ -6,7 +6,7 @@ module Color where
built-in names.
# Creation
@docs rgb, rgba, hsv, hsva, grayscale, greyscale
@docs rgb, rgba, hsv, hsva, greyscale, grayscale
# From Other Colors
@docs complement

View file

@ -52,28 +52,16 @@ have the equivalence: `(partition es == (lefts es, rights es))`
partition : [Either a b] -> ([a],[b])
partition es = List.foldr consEither ([],[]) es
{-| If `Left`, add the value to the front of the list.
If `Right`, return the list unchanged
-}
consLeft : Either a b -> [a] -> [a]
consLeft e vs =
case e of
Left v -> v::vs
Right _ -> vs
{-| If `Right`, add the value to the front of the list.
If `Left`, return the list unchanged.
-}
consRight : Either a b -> [b] -> [b]
consRight e vs =
case e of
Left _ -> vs
Right v -> v::vs
{-| If `Left`, add the value to the left list.
If `Right`, add the value to the right list.
-}
consEither : Either a b -> ([a], [b]) -> ([a], [b])
consEither e (ls,rs) =
case e of
Left l -> (l::ls,rs)

View file

@ -125,7 +125,7 @@ tiled to fill the entire shape.
textured : String -> Shape -> Form
textured src shape = fill (Texture src) shape
{-| Fill a shape with a [gradient](/docs/Color.elm#linear). -}
{-| Fill a shape with a [gradient](/library/Color.elm#linear). -}
gradient : Gradient -> Shape -> Form
gradient grad shape = fill (Grad grad) shape
@ -204,37 +204,37 @@ collage : Int -> Int -> [Form] -> Element
collage = Native.Graphics.Collage.collage
type Path = [(number,number)]
type Path = [(Float,Float)]
{-| Create a path that follows a sequence of points. -}
path : [(number,number)] -> Path
path : [(Float,Float)] -> Path
path ps = ps
{-| Create a path along a given line segment. -}
segment : (number,number) -> (number,number) -> Path
segment : (Float,Float) -> (Float,Float) -> Path
segment p1 p2 = [p1,p2]
type Shape = [(number,number)]
type Shape = [(Float,Float)]
{-| Create an arbitrary polygon by specifying its corners in order.
`polygon` will automatically close all shapes, so the given list
of points does not need to start and end with the same position.
-}
polygon : [(number,number)] -> Shape
polygon : [(Float,Float)] -> Shape
polygon points = points
{-| A rectangle with a given width and height. -}
rect : number -> number -> Shape
rect : Float -> Float -> Shape
rect w h = let hw = w/2
hh = h/2
in [ (0-hw,0-hh), (0-hw,hh), (hw,hh), (hw,0-hh) ]
{-| A square with a given edge length. -}
square : number -> Shape
square : Float -> Shape
square n = rect n n
{-| An oval with a given width and height. -}
oval : number -> number -> Shape
oval : Float -> Float -> Shape
oval w h =
let n = 50
t = 2 * pi / n
@ -244,7 +244,7 @@ oval w h =
in List.map f [0..n-1]
{-| A circle with a given radius. -}
circle : number -> Shape
circle : Float -> Shape
circle r = oval (2*r) (2*r)
{-| A regular polygon with N sides. The first argument specifies the number
@ -253,7 +253,7 @@ of sides and the second is the radius. So to create a pentagon with radius
ngon 5 30
-}
ngon : Int -> number -> Shape
ngon : Int -> Float -> Shape
ngon n r =
let m = toFloat n
t = 2 * pi / m

View file

@ -204,9 +204,8 @@ flow dir es =
DIn -> newFlow (List.maximum ws) (List.maximum hs)
DOut -> newFlow (List.maximum ws) (List.maximum hs)
{-| Stack elements vertically. To put `a` above `b` you would say:
a `above` b
{-| Stack elements vertically.
To put `a` above `b` you would say: ``a `above` b``
-}
above : Element -> Element -> Element
above hi lo =
@ -214,9 +213,8 @@ above hi lo =
(heightOf hi + heightOf lo)
(Flow DDown [hi,lo])
{-| Stack elements vertically. To put `a` below `b` you would say:
a `below` b
{-| Stack elements vertically.
To put `a` below `b` you would say: ``a `below` b``
-}
below : Element -> Element -> Element
below lo hi =
@ -225,6 +223,7 @@ below lo hi =
(Flow DDown [hi,lo])
{-| Put elements beside each other horizontally.
To put `a` beside `b` you would say: ``a `beside` b``
-}
beside : Element -> Element -> Element
beside lft rht =
@ -232,8 +231,8 @@ beside lft rht =
(max (heightOf lft) (heightOf rht))
(Flow right [lft,rht])
{-| Layer elements on top of each other, starting from the bottom.
`(layers == flow outward)`
{-| Layer elements on top of each other, starting from the bottom:
`layers == flow outward`
-}
layers : [Element] -> Element
layers es =

View file

@ -9,7 +9,7 @@ integration.
@docs toString, toInt, toFloat, toBool, toList
# JavaScript from Elm
@docs fromString, fromInt, fromFloat, fromBool fromList
@docs fromString, fromInt, fromFloat, fromBool, fromList
-}
{-
# DOM Nodes and Elements

View file

@ -39,11 +39,6 @@ isJust = maybe False (\_ -> True)
isNothing : Maybe a -> Bool
isNothing = not . isJust
{-| If `Just`, adds the value to the front of the list.
If `Nothing`, list is unchanged.
-}
cons : Maybe a -> [a] -> [a]
cons mx xs = maybe xs (\x -> x :: xs) mx
{-| Filters out Nothings and extracts the remaining values.

View file

@ -33,7 +33,7 @@ Elm.Native.Basics.make = function(elm) {
mod:mod,
pi:Math.PI,
e:Math.e,
e:Math.E,
cos:Math.cos,
sin:Math.sin,
tan:Math.tan,

View file

@ -21,7 +21,7 @@ Elm.Native.Show.make = function(elm) {
return v ? "True" : "False";
} else if (type === "number") {
return v+"";
} else if (v.isChar && v instanceof String) {
} else if ((v instanceof String) && v.isChar) {
return "'" + addSlashes(v) + "'";
} else if (type === "string") {
return '"' + addSlashes(v) + '"';

View file

@ -26,10 +26,6 @@ Elm.Native.Http.make = function(elm) {
}
}
function setHeader(pair) {
request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
}
function sendReq(queue,responses,req) {
var response = { value: { ctor:'Waiting' } };
queue.push(response);
@ -46,6 +42,9 @@ Elm.Native.Http.make = function(elm) {
}
};
request.open(JS.fromString(req.verb), JS.fromString(req.url), true);
function setHeader(pair) {
request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
}
List.map(setHeader)(req.headers);
request.send(JS.fromString(req.body));
}

View file

@ -22,14 +22,24 @@ Elm.Native.String.make = function(elm) {
return (hd = str[0]) ? Maybe.Just(Utils.Tuple2(Utils.chr(hd), str.slice(1)))
: Maybe.Nothing;
}
function append(a,b) {
return a + b;
}
function concat(strs) {
return JS.fromList(strs).join('');
}
function length(str) {
return str.length;
}
function map(f,str) {
return str.split('').map(f).join('');
var out = str.split('');
for (var i = out.length; i--; ) {
out[i] = f(Utils.chr(out[i]));
}
return out.join('');
}
function filter(pred,str) {
return str.split('').filter(pred).join('');
return str.split('').map(Utils.chr).filter(pred).join('');
}
function reverse(str) {
return str.split('').reverse().join('');
@ -37,13 +47,13 @@ Elm.Native.String.make = function(elm) {
function foldl(f,b,str) {
var len = str.length;
for (var i = 0; i < len; ++i) {
b = A2(f, str[i], b);
b = A2(f, Utils.chr(str[i]), b);
}
return b;
}
function foldr(f,b,str) {
for (var i = str.length; i--; ) {
b = A2(f, str[i], b);
b = A2(f, Utils.chr(str[i]), b);
}
return b;
}
@ -116,13 +126,13 @@ Elm.Native.String.make = function(elm) {
function any(pred, str) {
for (var i = str.length; i--; ) {
if (pred(str[i])) return true;
if (pred(Utils.chr(str[i]))) return true;
}
return false;
}
function all(pred, str) {
for (var i = str.length; i--; ) {
if (!pred(str[i])) return false;
if (!pred(Utils.chr(str[i]))) return false;
}
return true;
}
@ -147,8 +157,7 @@ Elm.Native.String.make = function(elm) {
return JS.toList(is);
}
function toInt(str) {
var s = JS.fromString(str);
function toInt(s) {
var len = s.length;
if (len === 0) { return Maybe.Nothing; }
var start = 0;
@ -162,8 +171,7 @@ Elm.Native.String.make = function(elm) {
return Maybe.Just(parseInt(s, 10));
}
function toFloat(str) {
var s = JS.fromString(str);
function toFloat(s) {
var len = s.length;
if (len === 0) { return Maybe.Nothing; }
var start = 0;
@ -183,10 +191,19 @@ Elm.Native.String.make = function(elm) {
return Maybe.Just(parseFloat(s));
}
function toList(str) {
return JS.toList(str.split('').map(Utils.chr));
}
function fromList(chars) {
return JS.fromList(chars).join('');
}
return Elm.Native.String.values = {
isEmpty: isEmpty,
cons: F2(cons),
uncons: uncons,
append: F2(append),
concat: concat,
length: length,
map: F2(map),
filter: F2(filter),
@ -228,5 +245,7 @@ Elm.Native.String.make = function(elm) {
toInt: toInt,
toFloat: toFloat,
toList: toList,
fromList: fromList,
};
};

View file

@ -3,7 +3,7 @@ module Random where
{-| Since the core of Elm is pure, randomness must be handled via signals.
# Random Numbers
@docs range, float
@docs range, float, floatList
-}
import Signal (Signal)

View file

@ -15,15 +15,15 @@ the [`Time`](/docs/Signal/Time.elm) library.
# Combine
@docs constant, lift, lift2, merge, merges, combine
# Pretty Lift
@docs (<~), (~)
# Past-Dependence
@docs foldp, count, countIf
#Filters
@docs keepIf, dropIf, keepWhen, dropWhen, dropRepeats, sampleOn
# Pretty Lift
@docs (<~), (~)
# Do you even lift?
@docs lift3, lift4, lift5, lift6, lift7, lift8

View file

@ -3,11 +3,10 @@ module String where
are enclosed in `"double quotes"`. Strings are *not* lists of characters.
# Basics
@docs isEmpty, length, cons, uncons, reverse,
map, filter, foldl, foldr, any, all, repeat
@docs isEmpty, length, reverse, repeat
# Split and Join
@docs split, join, words, lines
# Building and Splitting
@docs cons, uncons, append, concat, split, join, words, lines
# Get Substrings
@docs sub, left, right, dropLeft, dropRight
@ -15,8 +14,8 @@ are enclosed in `"double quotes"`. Strings are *not* lists of characters.
# Check for Substrings
@docs contains, startsWith, endsWith, indexes, indices
# Conversion To Numbers
@docs toInt, toFloat
# Conversions
@docs toInt, toFloat, toList, fromList
# Formatting
Cosmetic operations such as padding with extra characters or trimming whitespace.
@ -24,6 +23,9 @@ Cosmetic operations such as padding with extra characters or trimming whitespace
@docs toUpper, toLower,
pad, padLeft, padRight,
trim, trimLeft, trimRight
# Higher-Order Functions
@docs map, filter, foldl, foldr, any, all
-}
import Native.String
@ -46,6 +48,21 @@ pattern match on strings exactly as you would with lists.
uncons : String -> Maybe (Char, String)
uncons = Native.String.uncons
{-| Append two strings. You can also use [the `(++)` operator](/library/List.elm#++)
to do this.
append "butter" "fly" == "butterfly"
-}
append : String -> String -> String
append = Native.String.append
{-| Concatenate many strings into one.
concat ["never","the","less"] == "nevertheless"
-}
concat : [String] -> String
concat = Native.String.concat
{-| Get the length of a string `(length "innumerable" == 11)` -}
length : String -> Int
length = Native.String.length
@ -68,12 +85,16 @@ filter = Native.String.filter
reverse : String -> String
reverse = Native.String.reverse
{-|
{-| Reduce a string from the left:
foldl cons "" "time" == "emit"
-}
foldl : (Char -> b -> b) -> b -> String -> b
foldl = Native.String.foldl
{-|
{-| Reduce a string from the right:
foldr cons "" "time" == "time"
-}
foldr : (Char -> b -> b) -> b -> String -> b
foldr = Native.String.foldr
@ -272,3 +293,19 @@ toInt = Native.String.toInt
-}
toFloat : String -> Maybe Float
toFloat = Native.String.toFloat
{-| Convert a string to a list of characters.
toList "abc" == ['a','b','c']
-}
toList : String -> [Char]
toList = Native.String.toList
{-| Convert a list of characters into a String. Can be useful if you
want to create a string primarly by consing, perhaps for decoding
something.
fromList ['a','b','c'] == "abc"
-}
fromList : String -> [Char]
fromList = Native.String.fromList

View file

@ -39,8 +39,8 @@ return {addTo:addTo,
newElement:newElement,
extract : extract,
fromList: List.toArray,
fromString: function(s) { return List.toArray(s).join(''); },
toString: List.fromArray,
fromString: function(s) { return s; },
toString: function(s) { return s; },
eq: Elm.Native.Utils.make({}).eq,
addTransform: addTransform,
removeTransform: removeTransform

View file

@ -1,5 +1,5 @@
Name: elm-server
Version: 0.9.0.2
Version: 0.10
Synopsis: The Elm language server.
Description: This package provides a standalone, Happstack-based Elm server.
@ -36,5 +36,5 @@ Executable elm-server
happstack-server,
deepseq,
filepath,
Elm >= 0.9.0.2,
Elm >= 0.10,
process