Last active
July 7, 2022 18:26
-
-
Save Mesabloo/95e7bee4eba9bf75b59e9c5f67df212b to your computer and use it in GitHub Desktop.
A simple exercise with Haskell and genericity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-| Exercise: | |
- Step 1: | |
Write a program simulating an iterating machine: we for example feed a range | |
@[0..4]@ and an action @print@ and it must execute this action on all the | |
elements of the range. | |
Writing @iterate1 [4..9] print@ must output: | |
> 4 | |
> 5 | |
> 6 | |
> 7 | |
> 8 | |
> 9 | |
- Step 2: | |
Now, we want to iterate on two ranges. Each action also has to take 2 parameters now. | |
We can consider using @(,)@ and having @type Action a b c = (a, b) -> c@. | |
Writing @iterate2 [1..3] [1..3] print@ must output: | |
> (1, 1) | |
> (1, 2) | |
> (1, 3) | |
> (2, 1) | |
> (2, 2) | |
> (2, 3) | |
> (3, 1) | |
> (3, 2) | |
> (3, 3) | |
- Step 3: | |
We would like to add filters on the ranges now. Any couple not satisfying the predicate should not be treated. | |
Writing @iterate2Predicate [1..3] [1..3] print (uncurry (==))@ must output: | |
> (1, 1) | |
> (2, 2) | |
> (3, 3) | |
- Step 4: | |
Let's make everything work on any number of ranges and any number of predicates | |
and any number of actions (both can possibly be 0). | |
Writing @iterateNPredicates [[1..3],[1..3]] [print] [\ [x, y] -> x == y, \ [x, _] -> even x]@ must output: | |
> [2, 2] | |
-} | |
{-# LANGUAGE RankNTypes #-} | |
{-# LANGUAGE KindSignatures #-} | |
import Control.Monad (void) | |
main :: IO () | |
main = void $ | |
mapsWithRangeAndPredicatesN | |
[[1..4],[1..4],[1..4]] | |
[print,print,print] | |
[\ (x:y:_) -> x == y, \ [_, _, z] -> even z] | |
------------------------------------------------------------------------- | |
mapWithRange1 | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [a] | |
-> (a -> m b) | |
-> m [b] | |
mapWithRange1 range f = mapWithRangeAndPredicate1 range f (const True) | |
mapWithRangeAndPredicate1 | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [a] | |
-> (a -> m b) | |
-> (a -> Bool) | |
-> m [b] | |
mapWithRangeAndPredicate1 range f pred = | |
mapWithRangeAndPredicateN [range] (f . listToTuple1) (pred . listToTuple1) | |
where listToTuple1 [x] = x | |
mapWithRange2 | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [a] | |
-> [a] | |
-> (a -> a -> m b) | |
-> m [b] | |
mapWithRange2 range1 range2 f = mapWithRangeAndPredicate2 range1 range2 f (const (const True)) | |
mapWithRangeAndPredicate2 | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [a] | |
-> [a] | |
-> (a -> a -> m b) | |
-> (a -> a -> Bool) | |
-> m [b] | |
mapWithRangeAndPredicate2 range1 range2 f pred = | |
mapWithRangeAndPredicateN [range1, range2] (uncurryList2 f) (uncurryList2 pred) | |
where uncurryList2 g [x, y] = g x y | |
mapWithRangeN | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [[a]] | |
-> ([a] -> m b) | |
-> m [b] | |
mapWithRangeN ranges f = mapWithRangeAndPredicateN ranges f (const True) | |
mapWithRangeAndPredicateN | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [[a]] | |
-> ([a] -> m b) | |
-> ([a] -> Bool) | |
-> m [b] | |
mapWithRangeAndPredicateN ranges f pred = mapsWithRangeAndPredicateN ranges [f] pred | |
mapsWithRangeN | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [[a]] | |
-> [[a] -> m b] | |
-> m [b] | |
mapsWithRangeN ranges actions = mapsWithRangeAndPredicateN ranges actions (const True) | |
mapsWithRangeAndPredicateN | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [[a]] | |
-> [[a] -> m b] | |
-> ([a] -> Bool) | |
-> m [b] | |
mapsWithRangeAndPredicateN ranges actions pred = mapsWithRangeAndPredicatesN ranges actions [pred] | |
mapsWithRangeAndPredicatesN | |
:: forall (m :: * -> *) a b. | |
(Monad m, Enum a) | |
=> [[a]] | |
-> [[a] -> m b] | |
-> [[a] -> Bool] | |
-> m [b] | |
mapsWithRangeAndPredicatesN ranges actions preds = sequence [ f x | x <- cartN ranges, f <- actions, and $ ($ x) <$> preds ] | |
cartN :: [[a]] -> [[a]] | |
cartN [] = [ ] | |
cartN [l] = [ [x] | x <- l ] | |
cartN [l1, l2] = [ [x, y] | x <- l1, y <- l2 ] | |
cartN (l1:l2:r) = [ x <> y | x <- cartN [l1, l2], y <- cartN r ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment