packages feed

arrow-utils (empty) → 0.1.0.0

raw patch · 5 files changed

+214/−0 lines, 5 filesdep +QuickCheckdep +arrow-utilsdep +base

Dependencies added: QuickCheck, arrow-utils, base, test-framework, test-framework-quickcheck2, vector-sized

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for arrow-utils++## 0.1.0.0 -- 2021-06-?++* First version.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2021, Miguel Negrão++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Miguel Negrão nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ arrow-utils.cabal view
@@ -0,0 +1,41 @@+cabal-version:      >=1.10+name:               arrow-utils+version:            0.1.0.0+synopsis: functions for working with arrows+description:+ arrow-utils provides useful functions and type classes for working with arrows. It provides functions similar to sequenceA.+++license:            BSD3+license-file:       LICENSE+author:             Miguel Negrão+maintainer:         miguel.negrao@friendlyvirus.org+homepage:           https://github.com/miguel-negrao/+category:           Arrows, Control, Combinators+build-type:         Simple+extra-source-files: CHANGELOG.md++library+    exposed-modules:+        Control.Arrow.Utils+    other-extensions:+        Arrows+    build-depends:+          base  == 4.14.* +        , vector-sized == 1.4.*+    hs-source-dirs:   src+    default-language: Haskell2010+++test-suite test+  type: exitcode-stdio-1.0+  main-is: Main.hs+  hs-source-dirs: test+  build-depends:+      base  == 4.14.*+    , arrow-utils+    , test-framework == 0.8.*+    , test-framework-quickcheck2 == 0.3.*+    , QuickCheck == 2.14.*+    +  default-language:    Haskell2010
+ src/Control/Arrow/Utils.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE Arrows #-}++module Control.Arrow.Utils (+    SameInputArrow(..)+  , traverseArr+  , traverseArr_+  , sequenceArr_+  , sequenceArr+  , zipSequenceArrVec+  , zipSequenceArrList+  , whenArr+  , unlessArr+  , constantly+) where++import Control.Arrow+    ( returnA, (>>>), Arrow((***), arr), ArrowChoice )+import Data.Foldable (traverse_)+import Data.Maybe ( fromJust )+import Data.Vector.Sized ( fromList, toList, Vector )+import qualified Data.Vector.Sized as Vec+import GHC.TypeLits ( KnownNat )++-- | Wrap the Arrow in a newtype in order to create new class instances.+--   This is a generalisation of 'ArrowMonad',+--   which is isomorphic to @'SameInputArrow' a () c@.+newtype SameInputArrow a b c = SameInputArrow { unSameInputArrow :: a b c }++-- | @'fmap' f@ postcomposes with @f@+instance (Arrow a) => Functor (SameInputArrow a b) where+  fmap f a = SameInputArrow (unSameInputArrow a >>> arr f)++-- | @'<*>'@ runs the arrows in parallel+instance (Arrow a) => Applicative (SameInputArrow a b) where+  pure c = SameInputArrow $ constantly c+  f <*> a = SameInputArrow $ proc input -> do+    fres <- unSameInputArrow f -< input+    ares <- unSameInputArrow a -< input+    returnA -< fres ares++-- | Creates arrows using f, then runs all arrows in the given 'Foldable',+-- discarding the results.+traverseArr_ :: (Foldable t, Arrow a) => (x -> a b c) -> t x -> a b ()+traverseArr_ f xs = unSameInputArrow $ traverse_ (SameInputArrow . f) xs++-- | Creates arrows using f, then runs all arrows in the given 'Traversable',+-- collecting the results.+--+--   @traverseArr (+) [1,10] 1 == [2,11]@+traverseArr :: (Traversable t, Arrow a) => (x -> a b c) -> t x -> a b (t c)+traverseArr f xs = unSameInputArrow $ traverse (SameInputArrow . f) xs++-- | Like 'sequenceArr', but discard the results.+sequenceArr_ :: (Foldable t, Arrow a) => t (a b any) -> a b ()+sequenceArr_ = traverseArr_ id++-- | Run all arrows in the given 'Traversable', collecting the results.+--+--   @sequenceArr [(+1), (+10)] 1 == [2,11]@+sequenceArr :: (Traversable t, Arrow a) => t (a b c) -> a b (t c)+sequenceArr = traverseArr id++-- | Fans each input from @Vector n b@ to a separate arrow from the given vector.+--+--   @sequenceArrVec (Vec.generate ((+).fromIntegral) :: Vector 5 (Int -> Int)) (Vec.replicate 1 :: Vector 5 Int) == Vector [1,2,3,4,5]@+zipSequenceArrVec :: (Arrow a, KnownNat n) => Vector n (a b c) -> a (Vector n b) (Vector n c)+zipSequenceArrVec cells = arr toList >>> zipSequenceArrListUnsafe (toList cells) >>> arr (fromJust . fromList)++-- Not safe, doesn't check size of the lists.+-- When used in sequenceArrVec it is safe as the size of the+-- vectors are all the same. Not to export.+zipSequenceArrListUnsafe :: Arrow a => [a b c] -> a [b] [c]+zipSequenceArrListUnsafe [] = constantly []+zipSequenceArrListUnsafe (x:xs) = proc (y:ys) -> do+  xres <- x -< y+  xsres <- zipSequenceArrListUnsafe xs -< ys+  returnA -< (xres:xsres)++-- | Fans each input from @[b]@ to a separate arrow from the given list.+--   The output list has length of the minimum of the input list length and the arrow list length.+--+--  @+--  sequenceArrList [(+1), (+10)] [1,2] == [2,12]+--  sequenceArrList [(+1), (+10)] [1]   == [2]+--  sequenceArrList [(+1)] [1,2,3,4]    == [2]@+zipSequenceArrList :: (Arrow a, ArrowChoice a) => [a b c] -> a [b] [c]+zipSequenceArrList [] = constantly []+zipSequenceArrList (a : as) = proc bs' -> case bs' of+  [] -> returnA -< []+  b : bs -> do+    c <- a -< b+    cs <- zipSequenceArrList as -< bs+    returnA -< c : cs++-- | Similar to @'when'@ for @'Applicative'@. Relevant for+--   arrows which embeded a Monad.+whenArr :: ArrowChoice a => a b () -> a (Bool, b) ()+whenArr cell = proc (b, input) -> do+  if b+    then cell -< input+    else constantly () -< input++-- | Similar to @'unless'@ for @'Applicative'@. Relevant for+--   arrows which embeded a Monad.+unlessArr :: ArrowChoice a => a b () -> a (Bool, b) ()+unlessArr cell = arr not *** arr id >>> whenArr cell++-- | Always output the given value.+constantly :: Arrow a => b -> a any b+constantly = arr . const
+ test/Main.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE ScopedTypeVariables #-}++-- test-framework+import Test.Framework ( testGroup, defaultMain, Test )++-- test-framework-quickcheck2+import Test.Framework.Providers.QuickCheck2 ( testProperty )++-- QuickCheck+import Test.QuickCheck ( (===) )++import Control.Arrow.Utils ( zipSequenceArrList )++main :: IO ()+main = defaultMain tests++tests :: [Test.Framework.Test]+tests = [+  testGroup "sequenceArrList"+    [ testProperty "length of arrows"+      $ \(xs :: [Integer]) (ys :: [Integer])-> let+         funcList = fmap (const (+1)) ys+         res = zipSequenceArrList funcList xs+        in+          length res === min (length xs) (length ys)                           +    ]+  ]+