on master help sign in
Merge pull request #595 from maxsnew/list-funs

List Function Performance and Testing Improvements

commit8928784cb6c8012f14cd369811a8b62ec86513f7 authorEvan Czaplicki <info@elm-lang.org> dateFri 25 Apr 2014, 03:45 (13 years ago) parent3fe77a66e4bcf0
6 files changed+93−39
libraries/List.elm+17−14 libraries/Native/Utils.js+21−14 tests/elm/Test.elm+6−4 tests/elm/Test/List.elm+38 tests/elm/Test/Set.elm+6−5 tests/hs/LibTest.hs+5−2
libraries/List.elm+17−14
@@ -171,11 +171,11 @@ not.
171171 partition isEven [0..5] == ([0,2,4], [1,3,5])
172172-}
173173partition : (a -> Bool) -> [a] -> ([a],[a])
174−partition pred lst =
175− case lst of
176− [] -> ([],[])
177− x::xs -> let (bs,cs) = partition pred xs in
178− if pred x then (x::bs,cs) else (bs,x::cs)
174+partition pred =
175+ let step x (ts, fs) = if pred x
176+ then (x::ts, fs)
177+ else (ts, x::fs)
178+ in foldr step ([],[])
179179
180180{-| Combine two lists, combining them into tuples pairwise.
181181If one list is longer, the extra elements are dropped.
@@ -194,12 +194,13 @@ If one list is longer, the extra elements are dropped.
194194zipWith : (a -> b -> c) -> [a] -> [b] -> [c]
195195zipWith = Native.List.zipWith
196196
197−{-| Decompose a list of tuples. -}
197+{-| Decompose a list of tuples.
198+ unzip [(0, True), (17, False), (1337, True)] == ([0,17,1337], [True,False,True])
199+-}
198200unzip : [(a,b)] -> ([a],[b])
199−unzip pairs =
200− case pairs of
201− [] -> ([],[])
202− (x,y)::ps -> let (xs,ys) = (unzip ps) in (x::xs,y::ys)
201+unzip =
202+ let step (x,y) (xs, ys) = (x::xs, y::ys)
203+ in foldr step ([], [])
203204
204205{-| Places the given value between all of the lists in the second
205206argument and concatenates the result.
@@ -215,10 +216,12 @@ join = Native.List.join
215216-}
216217intersperse : a -> [a] -> [a]
217218intersperse sep xs =
218− case xs of
219− a::b::cs -> a :: sep :: intersperse sep (b::cs)
220− [a] -> [a]
221− [] -> []
219+ case xs of
220+ [] -> []
221+ hd::tl ->
222+ let step x rest = sep :: x :: rest
223+ spersed = foldr step [] tl
224+ in hd :: spersed
222225
223226{-| Take the first n members of a list: `(take 2 [1,2,3,4] == [1,2])` -}
224227take : Int -> [a] -> [a]
libraries/Native/Utils.js+21−14
@@ -5,23 +5,30 @@ Elm.Native.Utils.make = function(elm) {
55 elm.Native.Utils = elm.Native.Utils || {};
66 if (elm.Native.Utils.values) return elm.Native.Utils.values;
77
8− function eq(x,y) {
9− if (x === y) return true;
10− if (typeof x === "object") {
11− var c = 0;
12− for (var i in x) {
13− ++c;
14− if (!eq(x[i],y[i])) {
15− return false;
8+ function eq(l,r) {
9+ var stack = [{'x': l, 'y': r}]
10+ while (stack.length > 0) {
11+ var front = stack.pop();
12+ var x = front.x;
13+ var y = front.y;
14+ if (x === y) continue;
15+ if (typeof x === "object") {
16+ var c = 0;
17+ for (var i in x) {
18+ ++c;
19+ stack.push({ 'x': x[i], 'y': y[i] });
1620 }
21+ if (c !== Object.keys(y).length) {
22+ return false;
23+ };
24+ } else if (typeof x === 'function') {
25+ throw new Error('Equality error: general function equality is ' +
26+ 'undecidable, and therefore, unsupported');
27+ } else {
28+ return false;
1729 }
18− return c === Object.keys(y).length;
19− }
20− if (typeof x === 'function') {
21− throw new Error('Equality error: general function equality is ' +
22− 'undecidable, and therefore, unsupported');
2330 }
24− return x === y;
31+ return true;
2532 }
2633
2734 // code in Generate/JavaScript.hs depends on the particular
tests/elm/Test.elm+6−4
@@ -9,13 +9,15 @@ import IO.IO (..)
99import IO.Runner (Request, Response)
1010import IO.Runner as Run
1111
12−import Test.String as String
13−import Test.Trampoline as Trampoline
1412import Test.Array as Array
1513import Test.Dict as Dict
16−
14+import Test.List as List
15+import Test.Set as Set
16+import Test.String as String
17+import Test.Trampoline as Trampoline
18+
1719tests : [Test]
18−tests = String.tests ++ Trampoline.tests ++ Array.tests ++ Dict.tests
20+tests = String.tests ++ Trampoline.tests ++ Array.tests ++ Dict.tests ++ Set.tests ++ List.tests
1921
2022console : IO ()
2123console = runDisplay tests
tests/elm/Test/List.elmnew file+38
@@ -0,0 +1,38 @@
1+module Test.List (tests) where
2+
3+import List
4+
5+import ElmTest.Assertion (..)
6+import ElmTest.Test (..)
7+
8+tests : [Test]
9+tests =
10+ let partitionTests =
11+ let p1 = id
12+ p2 x = x < 3
13+ isEven n = n `mod` 2 == 0
14+ in [ test "simple partition" <| assertEqual ([True],[False]) (List.partition p1 [False, True]),
15+ test "order check" <| assertEqual ([2,1], [5,6]) (List.partition p2 [2,5,6,1]),
16+ test "partition doc check 1" <| assertEqual ([0,1,2], [3,4,5]) (partition p2 [0..5]),
17+ test "partition doc check 2" <| assertEqual ([0,2,4], [1,3,5]) (partition isEven [0..5]),
18+ let n = 100000
19+ ts = repeat n True
20+ fs = repeat n False
21+ in test "partition stress test" <| assertEqual (ts, fs) (partition p1 (fs++ts))
22+ ]
23+ unzipTests = [
24+ test "unzip doc check" <| assertEqual ([0,17,1337],[True,False,True]) (unzip [(0, True), (17, False), (1337, True)]),
25+ let n = 100000
26+ ts = repeat n True
27+ fs = repeat n False
28+ in test "unzip stress test" <| assertEqual (ts, fs) (unzip (zip ts fs))
29+ ]
30+ intersperseTests = [
31+ test "intersperse doc check" <| assertEqual ["turtles","on","turtles","on","turtles"] (intersperse "on" ["turtles","turtles","turtles"]),
32+ let n = 100000
33+ ts = repeat n True
34+ fs = repeat n False
35+ in test "intersperse stress test" <| assertEqual (tail . List.concat <| zipWith (\x y -> [x,y]) fs ts)
36+ (intersperse False ts)
37+ ]
38+ in List.concat [partitionTests, unzipTests, intersperseTests]
tests/elm/Test/Set.elm+6−5
@@ -1,18 +1,19 @@
11module Test.Set (tests) where
22
33import Set
4+import Set (Set)
45import List
56
67import ElmTest.Assertion (..)
78import ElmTest.Test (..)
89
9−set : Set
10+set : Set Int
1011set = Set.fromList [1..100]
1112
12−setPart1 : Set
13+setPart1 : Set Int
1314setPart1 = Set.fromList [1..50]
1415
15−setPart2 : Set
16+setPart2 : Set Int
1617setPart2 = Set.fromList [51..100]
1718
1819pred : Int -> Bool
@@ -21,6 +22,6 @@ pred x = x <= 50
2122tests : [Test]
2223tests =
2324 let
24− filterTests = [assertEqual setPart1 <| filter pred set]
25− partitionTests = [assertEqual (setPart1, setPart2) <| partition pred set]
25+ filterTests = [test "Simple filter" <| assertEqual setPart1 <| Set.filter pred set]
26+ partitionTests = [test "Simple partition" <| assertEqual (setPart1, setPart2) <| Set.partition pred set]
2627 in List.concat [partitionTests, filterTests]
tests/hs/LibTest.hs+5−2
@@ -1,5 +1,7 @@
11module Main where
22
3+import Control.Monad (unless)
4+import Data.List (isInfixOf)
35import System.Directory
46import System.Exit
57import System.FilePath
@@ -11,8 +13,9 @@ main :: IO ()
1113main = do
1214 top <- getCurrentDirectory
1315 let ioScript s = top</>"IO"</>s
14− runCmd "git submodule init"
15− runCmd "npm install jsdom"
16+ runCmd "git submodule update --init"
17+ out <- readProcess "npm" ["ls", "--parseable"] ""
18+ unless ("jsdom" `isInfixOf` out) $ runCmd "npm install jsdom"
1619 setCurrentDirectory $ top</>"tests"</>"elm"
1720 runCmd $ concat [top</>"dist"</>"build"</>"elm"</>"elm --make --only-js --src-dir=" , top</>"automaton", " --src-dir=", top</>"IO", " --src-dir=", top</>"Elm-Test", " Test.elm"]
1821 runCmd $ unwords ["cat ", ioScript "prescript.js", Elm.runtime, "build"</>"Test.js", ioScript "handler.js", "> exe.js"]