Skip to content

Instantly share code, notes, and snippets.

@shamansir
Forked from anonymous/Main.elm
Last active May 16, 2017 21:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shamansir/281b35e117e601d232d28130250569c7 to your computer and use it in GitHub Desktop.
Save shamansir/281b35e117e601d232d28130250569c7 to your computer and use it in GitHub Desktop.
iterateMap, iterateOr, iterateAnd, iterateMapAnd, iterateWhileAnd in Elm
module UtilsTest exposing (suite)
import Test exposing (..)
import Expect
import Utils exposing (..)
suite : Test
suite =
describe "utils"
[ testReduce
, testIterateMap
, testIterateOr
, testIterateAnd
, testIterateMapAnd
, testIterateWhileAnd
]
testReduce : Test
testReduce =
describe "reduce"
[ test "should iterate through a list while function returns something" <|
(\() ->
Expect.equal
3
(reduce -1 [ 0, 1, 2, 3 ]
(\n _ -> Just n))
)
, test "should stop when function returns `Nothing`" <|
(\() ->
Expect.equal
1
(reduce -1 [ 0, 1, 2, 3 ]
(\n _ -> if n < 2 then Just n else Nothing))
)
, test "should return initial value when first element returned nothing" <|
(\() ->
Expect.equal
-1
(reduce -1 [ 0, 1, 2, 3 ] (\_ _ -> Nothing) )
)
, test "should be able to join items" <|
(\() ->
Expect.equal
5
(reduce -1 [ 0, 1, 2, 3 ]
(\n prevN -> Just (n + prevN)))
)
, test "should provide access to previous items" <|
(\() ->
Expect.equal
[ 1, 2, 3, 4 ]
(reduce [] [ 0, 1, 2, 3 ]
(\n prev -> Just (prev ++ [ n + 1 ])))
)
, test "should work with strings" <|
(\() ->
Expect.equal
"3/2/1/0/"
(reduce "" [ 0, 1, 2, 3 ]
(\n prev -> Just (toString n ++ "/" ++ prev)))
)
]
testIterateMap : Test
testIterateMap =
describe "iterateMap"
[ test "should be able to get all elements while function returns something" <|
(\() ->
Expect.equal
[ 0, 1, 2, 3 ]
(iterateMap (\n -> Just n) [ 0, 1, 2, 3 ])
)
, test "should apply what mapping function returns" <|
(\() ->
Expect.equal
[ 10, 11, 12, 13 ]
(iterateMap (\n -> Just (n + 10)) [ 0, 1, 2, 3 ])
)
, test "should stop when mapping function returns `Nothing`" <|
(\() ->
Expect.equal
[ 0, 1 ]
(iterateMap
(\n -> if (n < 2) then Just n else Nothing )
[ 0, 1, 2, 3 ])
)
, test "should return empty array when function returned `Nothing` for the first element" <|
(\() ->
Expect.equal
[ ]
(iterateMap
(\n -> if (n < 0) then Just n else Nothing )
[ 0, -1, -2, -3 ])
)
, test "should apply mapping function despite being stopped by `Nothing`" <|
(\() ->
Expect.equal
[ -10, -9, -8 ]
(iterateMap
(\n -> if (n < 3) then Just (n - 10) else Nothing )
[ 0, 1, 2, 3 ])
)
]
testIterateOr : Test
testIterateOr =
describe "iterateOr"
[ test "should get first element for which function returns something" <|
(\() ->
Expect.equal
(Just 0)
(iterateOr (\n -> Just n)
[ 0, 1, 2, 3 ])
)
, test "should get first element for which function returns something, p.II" <|
(\() ->
Expect.equal
(Just 2)
(iterateOr (\n -> if (n > 1) then Just n else Nothing)
[ 0, 1, 2, 3 ])
)
, test "should apply what mapping function returns" <|
(\() ->
Expect.equal
(Just 12)
(iterateOr (\n -> if (n > 1) then Just (n + 10) else Nothing)
[ 0, 1, 2, 3 ])
)
, test "should return `Nothing` when function returned `Nothing` for all the elements" <|
(\() ->
Expect.equal
Nothing
(iterateOr
(\n -> if (n > 10) then Just n else Nothing )
[ 0, 1, 2, 3 ])
)
]
testIterateAnd : Test
testIterateAnd =
describe "iterateAnd"
[ test "should return last successful element when function passes for all of them" <|
(\() ->
Expect.equal
(Just 3)
(iterateAnd (\n -> Just n)
[ 0, 1, 2, 3 ])
)
, test "should return `Nothing` when function not passes for one of the elements" <|
(\() ->
Expect.equal
Nothing
(iterateAnd (\n -> if (n > 0) then Just n else Nothing)
[ 0, 1, 2, 3 ])
)
, test "should apply what mapping function returns" <|
(\() ->
Expect.equal
(Just 13)
(iterateAnd (\n -> if (n > 1) then Just (n + 10) else Just (n - 10))
[ 0, 1, 2, 3 ])
)
, test "should return `Nothing` when function returned `Nothing` for all the elements" <|
(\() ->
Expect.equal
Nothing
(iterateAnd
(\n -> if (n > 10) then Just n else Nothing )
[ 0, 1, 2, 3 ])
)
]
testIterateMapAnd : Test
testIterateMapAnd =
describe "iterateMapAnd"
[ test "should return all values when function passes for all the elements" <|
(\() ->
Expect.equal
(Just [ 0, 1, 2, 3 ])
(iterateMapAnd (\n -> Just n)
[ 0, 1, 2, 3 ])
)
, test "should return `Nothing` when function not passes for one of the elements" <|
(\() ->
Expect.equal
Nothing
(iterateMapAnd (\n -> if (n > 0) then Just n else Nothing)
[ 0, 1, 2, 3 ])
)
, test "should return `Nothing` when function not passes for one of the elements, p. II" <|
(\() ->
Expect.equal
Nothing
(iterateMapAnd (\n -> if (n < 3) then Just n else Nothing)
[ 0, 1, 2, 3 ])
)
, test "should apply what mapping function returns" <|
(\() ->
Expect.equal
(Just [ -10, -9, 12, 13 ])
(iterateMapAnd (\n -> if (n > 1) then Just (n + 10) else Just (n - 10))
[ 0, 1, 2, 3 ])
)
, test "should return `Nothing` when function returned `Nothing` for all the elements" <|
(\() ->
Expect.equal
Nothing
(iterateMapAnd
(\n -> if (n > 10) then Just n else Nothing )
[ 0, 1, 2, 3 ])
)
]
testIterateWhileAnd : Test
testIterateWhileAnd =
describe "iterateWhileAnd"
[ test "should return last successful element when function passes for all of them" <|
(\() ->
Expect.equal
(Just 3)
(iterateWhileAnd (\n -> Just n)
[ 0, 1, 2, 3 ])
)
, test "should return `Nothing` when success chain in not bound to the start of the list" <|
(\() ->
Expect.equal
Nothing
(iterateWhileAnd (\n -> if (n > 0) then Just n else Nothing)
[ 0, 1, 2, 3 ])
)
, test "should return last element from the continuous chain of successes" <|
(\() ->
Expect.equal
(Just 2)
(iterateWhileAnd (\n -> if (n < 3) then Just n else Nothing)
[ 0, 1, 2, 3 ])
)
, test "should apply what mapping function returns" <|
(\() ->
Expect.equal
(Just 12)
(iterateWhileAnd (\n -> if (n < 3) then Just (n + 10) else Nothing)
[ 0, 1, 2, 3 ])
)
, test "should apply what mapping function returns, p. II" <|
(\() ->
Expect.equal
(Just 13)
(iterateWhileAnd (\n -> if (n > 1) then Just (n + 10) else Just (n - 10))
[ 0, 1, 2, 3 ])
)
, test "should return `Nothing` when function returned `Nothing` for all the elements" <|
(\() ->
Expect.equal
Nothing
(iterateWhileAnd
(\n -> if (n > 10) then Just n else Nothing )
[ 0, 1, 2, 3 ])
)
]
module Utils exposing (..)
import Tuple exposing (first)
import List exposing (foldl)
reduce : b -> List a -> (a -> b -> Maybe b) -> b
reduce init src reducer =
Tuple.first
(List.foldl
(\curVal (prevVal, prevContinue) ->
case prevContinue of
True -> case (reducer curVal prevVal) of
Just v -> (v, True)
Nothing -> (prevVal, False)
False -> (prevVal, False))
(init, True)
src)
-- executes the function for every item of `List a`, and while this
-- function returns `Just b`, add `b` instance to a resulting list,
-- but stops execution immediately when function returns `Nothing` for
-- the first time.
--
-- Example:
--
-- ```
-- (iterateMap
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 2, 1, 0, 1, 3, 5, 1, 0, 2, 3 ])
-- -> [ 102, 103, 100, 101, 103 ]
--
-- (iterateMap
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 5, 2, 1, 0, 1, 3, 1, 0, 2, 3 ])
-- -> [ ]
-- ```
iterateMap : (a -> Maybe b) -> List a -> List b
iterateMap f src =
reduce [] src
(\cur allValues ->
case (f cur) of
Just nextValue -> Just ( allValues ++ [ nextValue ] )
Nothing -> Nothing
)
-- execute the function for every item of `List a`, and when this
-- function returns `Just b` for the first time, return this `b` and
-- stop execution.
--
-- Example:
--
-- ```
-- (iterateOr
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 5, 2, 1, 0, 1, 3, 1, 0, -1, 3 ])
-- -> Just 102
--
-- (iterateOr
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 5, 7, 15, 12, 10, 24, 4, 6, 28 ])
-- -> Nothing
-- ```
iterateOr : (a -> Maybe b) -> List a -> Maybe b
iterateOr f src =
reduce Nothing src
(\cur hasValue ->
case hasValue of
Just v -> Just hasValue
Nothing -> case (f cur) of
Just v -> Just ( Just v )
Nothing -> Just Nothing
)
-- execute the function for every item of `List a`, return the last
-- succesful result only when the function returned `Just a` for all
-- the items from the list with no exceptions, else return `Nothing`.
--
-- Example:
--
-- ```
-- (iterateAnd
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 2, 1, 0, 1, 3 ])
-- -> Just 103
--
-- (iterateAnd
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 2, 1, 0, 1, 5 ])
-- -> Nothing
-- ```
iterateAnd : (a -> Maybe b) -> List a -> Maybe b
iterateAnd f src =
Tuple.second
(reduce ( True, Nothing ) src
(\cur ( hasValue, _ ) ->
case hasValue of
True -> case (f cur) of
Just v -> Just ( True, Just v )
Nothing -> Just ( False, Nothing )
False -> Just ( False, Nothing )
)
)
-- execute the function for every item of `List a`, return all the
-- collected results only when the function returned `Just a` for all
-- the items from the list with no exceptions, else return `Nothing`.
--
-- Example:
--
-- ```
-- (iterateMapAnd
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 2, 1, 0, 1, 3 ])
-- -> Just [ 102, 101, 100, 101, 103 ]
--
-- (iterateMapAnd
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 2, 1, 0, 1, 5 ])
-- -> Nothing
-- ```
iterateMapAnd : (a -> Maybe b) -> List a -> Maybe (List b)
iterateMapAnd f src =
Tuple.second
(reduce ( True, Nothing ) src
(\cur ( hasValue, maybeAllValues ) ->
case hasValue of
True -> case (f cur) of
Just nextValue ->
case maybeAllValues of
Just allValues -> Just ( True, Just ( allValues ++ [ nextValue ] ) )
Nothing -> Just ( True, Just [ nextValue ] )
Nothing -> Just ( False, Nothing )
False -> Just ( False, Nothing )
)
)
-- execute the function for every item of `List a`, and while this
-- function returns `Just b`, keeps last successful `b` instance to return,
-- but stop execution immediately when function returns `Nothing` for
-- the first time.
--
-- Example:
--
-- ```
-- (iterateWhileAnd
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 2, 1, 0, 1, 3, 5, 1, 0, 2, -1 ])
-- -> Just 103
--
-- (iterateWhileAnd
-- (\n -> if (n <= 3) then Just (n + 100) else Nothing)
-- [ 5, 2, 1, 0, 1, 3, 1, 0, 2, 3 ])
-- -> Nothing
-- ```
iterateWhileAnd : (a -> Maybe b) -> List a -> Maybe b
iterateWhileAnd f src =
Tuple.second
(reduce ( True, Nothing ) src
(\cur ( hasValue, maybeLastValue ) ->
case hasValue of
True -> case (f cur) of
Just v -> Just ( True, Just v )
Nothing -> case maybeLastValue of
Just lastValue -> Just ( False, Just lastValue )
Nothing -> Just ( False, Nothing )
False -> Just ( False, Nothing )
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment