Skip to content

Commit 47c9559

Browse files
afcondonLiamGoodacre
authored andcommitted
add instances for List and a couple of tests (#7)
* add instances for List and a couple of tests no tests for Witherable List or Witherable Array yet * fix error in List foldMap and formatting issues * replace non-performant snoc with Cons… …reverting to foldr.
1 parent 75d9ae3 commit 47c9559

File tree

4 files changed

+68
-15
lines changed

4 files changed

+68
-15
lines changed

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"purescript-foldable-traversable": "^3.0.0",
2222
"purescript-identity": "^3.0.0",
2323
"purescript-arrays": "^4.0.0",
24-
"purescript-either": "^3.0.0"
24+
"purescript-either": "^3.0.0",
25+
"purescript-lists": "^4.1.1"
2526
},
2627
"devDependencies": {
2728
"purescript-assert": "^3.0.0",

src/Data/Filterable.purs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ module Data.Filterable
1313
, cleared
1414
) where
1515

16-
import Prelude (const)
17-
import Control.Category ((<<<), id)
1816
import Control.Bind ((=<<))
19-
import Data.Semigroup ((<>))
17+
import Control.Category ((<<<), id)
18+
import Data.Array (partition, mapMaybe, filter) as Array
19+
import Data.Either (Either(..))
20+
import Data.Foldable (foldl, foldr)
2021
import Data.Functor (class Functor)
21-
import Data.Foldable (foldl)
22-
import Data.Monoid (class Monoid, mempty)
22+
import Data.List (List(..), filter, mapMaybe) as List
2323
import Data.Maybe (Maybe(..))
24-
import Data.Either (Either(..))
25-
import Data.Array (partition, mapMaybe, filter) as Array
24+
import Data.Monoid (class Monoid, mempty)
25+
import Data.Semigroup ((<>))
26+
import Prelude (const)
2627

2728
-- | `Filterable` represents data structures which can be _partitioned_/_filtered_.
2829
-- |
@@ -127,3 +128,24 @@ instance filterableEither :: Monoid m => Filterable (Either m) where
127128

128129
filter p = filterDefault p
129130

131+
instance filterableList :: Filterable List.List where
132+
-- partitionMap :: forall a l r. (a -> Either l r) -> List a -> { left :: List l, right :: List r }
133+
partitionMap p xs = foldr select { left: List.Nil, right: List.Nil } xs
134+
where
135+
select x { left, right } = case p x of
136+
Left l -> { left: List.Cons l left, right }
137+
Right r -> { left, right: List.Cons r right }
138+
139+
-- partition :: forall a. (a -> Boolean) -> List a -> { no :: List a, yes :: List a }
140+
partition p xs = foldr select { no: List.Nil, yes: List.Nil } xs
141+
where
142+
-- select :: (a -> Boolean) -> a -> { no :: List a, yes :: List a } -> { no :: List a, yes :: List a }
143+
select x { no, yes } = if p x
144+
then { no, yes: List.Cons x yes }
145+
else { no: List.Cons x no, yes }
146+
147+
-- filterMap :: forall a b. (a -> Maybe b) -> List a -> List b
148+
filterMap p = List.mapMaybe p
149+
150+
-- filter :: forall a. (a -> Boolean) -> List a -> List a
151+
filter = List.filter

src/Data/Witherable.purs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,18 @@ module Data.Witherable
1010
, module Data.Filterable
1111
) where
1212

13-
import Data.Unit (unit)
14-
import Control.Category ((<<<), id)
1513
import Control.Applicative (class Applicative, pure)
16-
import Data.Monoid (class Monoid, mempty)
17-
import Data.Identity (Identity(..))
14+
import Control.Category ((<<<), id)
15+
import Data.Either (Either(..))
1816
import Data.Filterable (class Filterable, partitioned, filtered)
1917
import Data.Functor (map)
20-
import Data.Either (Either(..))
18+
import Data.Identity (Identity(..))
19+
import Data.List (List)
2120
import Data.Maybe (Maybe(..))
21+
import Data.Monoid (class Monoid, mempty)
2222
import Data.Newtype (unwrap)
2323
import Data.Traversable (class Traversable, traverse)
24+
import Data.Unit (unit)
2425

2526
-- | `Witherable` represents data structures which can be _partitioned_ with
2627
-- | effects in some `Applicative` functor.
@@ -89,6 +90,10 @@ instance witherableArray :: Witherable Array where
8990
wilt p xs = map partitioned (traverse p xs)
9091
wither p xs = map filtered (traverse p xs)
9192

93+
instance witherableList :: Witherable List where
94+
wilt p xs = map partitioned (traverse p xs)
95+
wither p xs = map filtered (traverse p xs)
96+
9297
instance witherableMaybe :: Witherable Maybe where
9398
wilt p Nothing = pure { left: Nothing, right: Nothing }
9499
wilt p (Just x) = map convert (p x) where
@@ -108,4 +113,3 @@ instance witherableEither :: Monoid m => Witherable (Either m) where
108113
wither p (Right er) = map convert (p er) where
109114
convert Nothing = Left mempty
110115
convert (Just r) = Right r
111-

test/Main.purs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@ module Test.Main where
33
import Prelude
44
import Control.Monad.Eff (Eff)
55
import Control.Monad.Eff.Console (CONSOLE, log)
6-
import Data.Filterable (filter, filterMap)
6+
import Data.Either (Either(..))
7+
import Data.Filterable (filter, filterMap, partition, partitionMap)
78
import Data.Identity (Identity(Identity))
9+
import Data.List (List(Nil), (:))
810
import Data.Maybe (Maybe(..))
911
import Data.Witherable (wither)
1012
import Test.Assert (ASSERT, assert)
1113

14+
testEqNoYes :: a. (Ord a) => { no :: a, yes :: a } -> { no :: a, yes :: a } -> Boolean
15+
testEqNoYes { no: n1, yes: y1 } { no: n2, yes: y2 } =
16+
n1 == n2 && y1 == y2
17+
18+
testEqLeftRight :: a. (Ord a) => { left :: a, right :: a } -> { left :: a, right :: a } -> Boolean
19+
testEqLeftRight { left: l1, right: r1 } { left: l2, right: r2 } =
20+
l1 == l2 && r1 == r2
21+
22+
1223
main :: Eff (console :: CONSOLE, assert :: ASSERT) Unit
1324
main = do
1425
log "Test filterableMaybe instance" *> do
@@ -27,4 +38,19 @@ main = do
2738
assert $ wither pred (Just 5) == Identity Nothing
2839
assert $ wither pred Nothing == Identity Nothing
2940

41+
log "Test filterableList instance" *> do
42+
let pred x = if x > 5 then Just (x * 10) else Nothing
43+
let testlist = (1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : Nil)
44+
assert $ filterMap pred testlist == (60 : 70 : 80 : 90 : Nil)
45+
assert $ filter (_ > 5) testlist == (6 : 7 : 8 : 9 : Nil)
46+
assert $ partition (_ > 5) testlist `testEqNoYes` { no: (1 : 2 : 3 : 4 : 5 : Nil), yes: (6 : 7 : 8 : 9 : Nil)}
47+
assert $ (partitionMap Right $ (1 : 2 : 3 : 4 : 5 : Nil)).right == (1 : 2 : 3 : 4 : 5 : Nil)
48+
assert $ (partitionMap Left $ (1 : 2 : 3 : 4 : 5 : Nil)).left == (1 : 2 : 3 : 4 : 5 : Nil)
49+
50+
log "Test filterableArray instance" *> do
51+
let pred x = if x > 5 then Just (x * 10) else Nothing
52+
assert $ filterMap pred [1,2,3,4,5,6,7,8,9] == [60,70,80,90]
53+
assert $ filter (_ > 5) [1,2,3,4,5,6,7,8,9] == [6,7,8,9]
54+
assert $ partition (_ > 5) [1,2,3,4,5,6,7,8,9] `testEqNoYes` { no: [1,2,3,4,5], yes: [6,7,8,9]}
55+
3056
log "All done!"

0 commit comments

Comments
 (0)