The SelectionFoldable type represents a Foldable structure (eg. Array, List)
of items where zero or one of the items is selected.
Also provided is the
SelectionFoldableWithData type, which also keeps some user-provided data along
with the selected item (the SelectionFoldable type is actually just a type
alias for a SelectionFoldableWithData where there is no data).
Inspired by the excellent Elm list-selection package written by NoRedInk.
Note 1: All of the code examples in this README assume the following imports (common imports like Prelude are implicit):
import Data.SelectionFoldable as SF
import Data.SelectionFoldableWithData as SFWDNote 2: These examples use the # operator, which is left-to-right function
application:
1 # (\n -> n + 2) -- Add 2
-- 3
[1,2,3] # map (\n -> n + 1) -- Add one to each number
-- [2,3,4]
[1,2,3]
# map (\n -> n + 1) -- 1. Add one to each number, then
# map (\n -> n < 4) -- 2. Map the numbers to bools
-- [true,true,false]Any Foldable structure can be plugged in. Items and associated data can be of any type:
-- Using an Array:
x1 :: SF.SelectionFoldable Array Int
x1 = SF.fromFoldable [1,2,3]
-- Using a List:
x2 :: SF.SelectionFoldable List String
x2 = SF.fromFoldable (Cons "a" Nil)
-- This seems a bit silly, but it's possible!
x3 :: SF.SelectionFoldable Maybe Boolean
x3 = SF.fromFoldable (Just true)
-- Here `Bool` is the type of user-provided data associated with selected items.
-- The compiler will often require you to provide this type annotation.
x4 :: SFWD.SelectionFoldableWithData Array Bool Int
x4 = SFWD.fromFoldable [1,2,3]
-- Any types will work!
data Foo = A | B
x5 :: SFWD.SelectionFoldableWithData Array Foo Foo
x5 = SFWD.fromFoldable [A,B]Using select or selectIndex will select items by equality to the provided
item (this obviously requires an Eq instance for the item type):
x1 :: SF.SelectionFoldable Array Int
x1 = SF.fromFoldable [1,3,9] # SF.select 3 -- Selects the second element
-- SF.selected x1 = Just 3 :: Maybe Int
x2 :: SF.SelectionFoldable Array Int
x2 = SF.fromFoldable [1,3,9] # SF.select 2 -- Selects nothing
-- SF.selected x2 = Nothing :: Maybe Int
x3 :: SF.SelectionFoldable Array String
x3 = SF.fromFoldable ["a","b","c"] # SF.selectIndex 0 -- Selects the 'a'
-- SF.selected x3 = Just "a" :: Maybe String
x4 :: SF.SelectionFoldable Array Int
x4 = SF.fromFoldable [1,3,9] # SF.select 10 -- Selects nothing (out of bounds)
-- SF.selected x4 = Nothing :: Maybe Int
x4 :: SF.SelectionFoldableWithData Array String Int
x4 = SF.fromFoldable [1, 0, 2]
# SF.select "woo!" 2 -- Selects the 2, and stores the string "woo!" with it
-- SF.selected x4 = Just (Tuple "woo!" 2) :: Maybe (Tuple String Int)Using selectWith or selectWithIndex will select items using the provided
function:
x1 :: SF.SelectionFoldable Array Int
x1 = SF.fromFoldable [1,3,9]
# SF.selectWith (_ > 1) -- Selects the second element
-- SF.selected x1 = Just 3 :: Maybe Int
x2 :: SF.SelectionFoldable Array Int
x2 = SF.fromFoldable [1,3,9]
# SF.selectWith (_ < 1) -- Selects nothing
-- SF.selected x2 = Nothing :: Maybe Int
x3 :: SF.SelectionFoldable Array Int
x3 = SF.fromFoldable [1, 0, 2]
# SF.selectWithIndex (\i s -> i == s) -- Selects the 2
-- SF.selected x3 = Just 2 :: Maybe IntThis does not require an Eq instance for the item type to work:
data Foo = A | B -- no Eq instance for Foo
x1 :: SF.SelectionFoldable Array String
x1 = SF.fromFoldable [A, B]
# SF.selectWith (\x -> case x of
A -> false
B -> true
) -- selects the B
x2 :: Maybe Int
x2 = SF.selected x1
# map (\x -> case x of
A -> 1
B -> 2
) -- Just 2 :: Maybe IntThe selected item (if it exists) gets mapped as well as the items in the structure:
x1 :: SF.SelectionFoldable Array Int
x1 = SF.fromFoldable [1,3,9]
# SF.selectIndex 0 -- Selects the '1'
# map (\n -> n + 1)
-- SF.toFoldable x1 = [2,4,10] :: Array Int
-- SF.selected x1 = Just 2 :: Maybe Int
x2 :: SF.SelectionFoldable Array Bool
x2 = SF.fromFoldable [1,3,9]
# SF.select 10 -- Selects nothing (out of bounds)
# map (\n -> n + 1)
-- SF.toFoldable x1 = [2,4,10] :: Array Int
-- SF.selected x1 = Nothing :: Maybe IntSF.fromFoldable [1,2,3]
# SF.select 1
# SF.foldrSelected (\isSelected x z ->
if isSelected then
(show x <> "!") : z
else
(show x) : z
) []
-- ["1!","2","3"] :: Array String
SFWD.fromFoldable [1,2,3]
# SFWD.select "!" 1
# SFWD.foldrSelected
{ sel: \(Tuple s x) z -> (show x <> s) : z
, rest: \x z -> (show x) : z
} []
-- ["1!","2","3"] :: Array StringSee test/Test/Main.purs for further examples.
This guarantee comes out of the fact that the data constructor is private, and the exposed functions maintain the invariant.
Using the select function (or selectWith, etc) selects the first matching
item as expected:
xs = SF.fromFoldable [1,2,3] # SF.selectWith (\x -> x < 3)
SF.selected xs -- Just 1However, when using mapSelected (or foldrSelected) to map a function f
over a SelectionFoldable where the selected item appears more than once in the
list, true will be passed as the IsSelected argument for each instance of
the selected item:
-- Here, both the first and last elements are equal to the selected item.
xs = SF.fromFoldable [1,2,1] # SF.select 1
mapSelected (\isSelected x -> if isSelected then "a" else "b") xs
-- (SelectionFoldableWithData ["a","b","a"] Just (Tuple unit "a")))
-- Note how both the first and last items were treated as if they were selected- Install purescript:
npm install -g purescript - Install bower:
npm install -g bower - Install pulp:
npm install -g pulp - Install dependencies:
npm install && bower install - Run tests:
pulp test
Licensed under a BSD 3-Clause license
- Module documentation is published on Pursuit.