From b8100741ff0741ee0f90bde615d637d7e7ac8a49 Mon Sep 17 00:00:00 2001 From: Matthew Leon Date: Mon, 12 Jun 2017 14:48:29 +0100 Subject: [PATCH 1/2] wip --- src/Data/Iterable.js | 11 ++++++++ src/Data/Iterable.purs | 60 ++++++++++++++++++++++++++++++++++++++++++ test/Test/Main.purs | 7 +++++ 3 files changed, 78 insertions(+) create mode 100644 src/Data/Iterable.js create mode 100644 src/Data/Iterable.purs diff --git a/src/Data/Iterable.js b/src/Data/Iterable.js new file mode 100644 index 0000000..9f8e866 --- /dev/null +++ b/src/Data/Iterable.js @@ -0,0 +1,11 @@ +"use strict"; + +exports.arrayIndexImpl = function (arr) { + return function (i) { + return arr[i]; + } +}; + +exports.arrayLengthImpl = function (arr) { + return arr.length; +}; diff --git a/src/Data/Iterable.purs b/src/Data/Iterable.purs new file mode 100644 index 0000000..3e87685 --- /dev/null +++ b/src/Data/Iterable.purs @@ -0,0 +1,60 @@ +module Data.Iterable + ( class Iterable + , Iterator(..) + , ArrayIndex + , iterator + , foreach + , foldRec + ) where + +import Prelude +import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM, tailRecM2) + +class Iterable t s | t -> s where + iterator :: forall a. t a -> Iterator s a + +data Iterator s a = Iterator { + state :: s a, + get :: s a -> a, + next :: s a -> (Step (s a) Unit) +} + +foreach :: forall t s a m. Iterable t s => MonadRec m => (a -> m Unit) -> t a -> m Unit +foreach f = iterate f <<< iterator + +foldRec :: forall t s a b m. Iterable t s => MonadRec m => (a -> b -> m b) -> b -> t a -> m b +foldRec f accum = inject f accum <<< iterator + +iterate :: forall s a m. MonadRec m => (a -> m Unit) -> Iterator s a -> m Unit +iterate effect (Iterator { state: s, get: g, next: n}) = tailRecM go s + where go s' = effect (g s') *> pure (n s') + +inject :: forall s a b m. MonadRec m => (a -> b -> m b) -> b -> Iterator s a -> m b +inject effect accum (Iterator { state: s, get: g, next: n}) = + tailRecM2 go s accum + where + go :: s a -> b -> m (Step { a :: s a, b :: b } b) + go s' accum' = do + accum'' <- effect (g s') accum' + pure $ case n s' of + Loop s'' -> Loop {a: s'', b: accum''} + Done unit -> Done accum'' + +instance iterableArray :: Iterable Array ArrayIndex where + iterator arr = Iterator { + state: Index 0, + get: indexArray arr, + next: mkArrayNext (arrayLengthImpl arr - 1) + } + +newtype ArrayIndex a = Index Int + +foreign import arrayIndexImpl :: forall a. Array a -> Int -> a +foreign import arrayLengthImpl :: forall a. Array a -> Int + +indexArray :: forall a. Array a -> ArrayIndex a -> a +indexArray arr (Index i) = arrayIndexImpl arr i + +mkArrayNext :: forall a. Int -> ArrayIndex a -> Step (ArrayIndex a) Unit +mkArrayNext lastIndex (Index i) = + if i < lastIndex then Loop (Index (i + 1)) else Done unit diff --git a/test/Test/Main.purs b/test/Test/Main.purs index dc1ff24..08a528d 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -7,6 +7,7 @@ import Control.Monad.Eff.Console (CONSOLE, log, logShow) import Control.Monad.Rec.Class (Step(..), tailRec, tailRecM, tailRecM2) import Data.Either (Either(..)) +import Data.Iterable (foreach, foldRec) -- | Compute the nth triangle number triangle :: Int -> Eff (console :: CONSOLE) Int @@ -49,3 +50,9 @@ main = do logShow $ mutual 1000001 loop 1000000 logShow $ loopFunction 10000000 ({result:100, step:1}) + + log "fold" + foreach logShow [0, 1, 2, 3, 4] + + log "foldRec" + logShow =<< foldRec (\x y -> logShow y *> pure (x + y)) 0 [1, 2, 3, 4] From 2b88dada1514dd3516cd9be17c36c99054e4a96a Mon Sep 17 00:00:00 2001 From: Matthew Leon Date: Mon, 12 Jun 2017 17:27:46 +0100 Subject: [PATCH 2/2] tweak name of `arrayNext` --- src/Data/Iterable.purs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Iterable.purs b/src/Data/Iterable.purs index 3e87685..2a4f74d 100644 --- a/src/Data/Iterable.purs +++ b/src/Data/Iterable.purs @@ -44,7 +44,7 @@ instance iterableArray :: Iterable Array ArrayIndex where iterator arr = Iterator { state: Index 0, get: indexArray arr, - next: mkArrayNext (arrayLengthImpl arr - 1) + next: arrayNext (arrayLengthImpl arr - 1) } newtype ArrayIndex a = Index Int @@ -55,6 +55,6 @@ foreign import arrayLengthImpl :: forall a. Array a -> Int indexArray :: forall a. Array a -> ArrayIndex a -> a indexArray arr (Index i) = arrayIndexImpl arr i -mkArrayNext :: forall a. Int -> ArrayIndex a -> Step (ArrayIndex a) Unit -mkArrayNext lastIndex (Index i) = +arrayNext :: forall a. Int -> ArrayIndex a -> Step (ArrayIndex a) Unit +arrayNext lastIndex (Index i) = if i < lastIndex then Loop (Index (i + 1)) else Done unit