diff --git a/examples/Build.hs b/examples/Build.hs index b54f978..14c0dcb 100644 --- a/examples/Build.hs +++ b/examples/Build.hs @@ -2,7 +2,7 @@ module Build where import Control.Selective -import Control.Selective.Free.Rigid +import Control.Selective.Rigid.Free -- See Section 3 of the paper: -- https://www.staff.ncl.ac.uk/andrey.mokhov/selective-functors.pdf diff --git a/examples/Processor.hs b/examples/Processor.hs index 42e7856..00a40c1 100644 --- a/examples/Processor.hs +++ b/examples/Processor.hs @@ -1,9 +1,8 @@ -{-# LANGUAGE ConstraintKinds, DeriveFunctor - , LambdaCase, FlexibleContexts, FlexibleInstances, GADTs #-} +{-# LANGUAGE ConstraintKinds, DeriveFunctor, GADTs, FlexibleContexts, LambdaCase #-} module Processor where import Control.Selective -import Control.Selective.Free.Rigid +import Control.Selective.Rigid.Free import Data.Functor import Data.Int (Int16) import Data.Word (Word8) diff --git a/examples/Teletype/Rigid.hs b/examples/Teletype/Rigid.hs index 51b246a..1fe3eee 100644 --- a/examples/Teletype/Rigid.hs +++ b/examples/Teletype/Rigid.hs @@ -4,7 +4,7 @@ module Teletype.Rigid where import Prelude hiding (getLine, putStrLn) import qualified Prelude as IO import Control.Selective -import Control.Selective.Free.Rigid +import Control.Selective.Rigid.Free -- See Section 5.2 of the paper: -- https://www.staff.ncl.ac.uk/andrey.mokhov/selective-functors.pdf diff --git a/selective.cabal b/selective.cabal index cd4315d..e5f07ec 100644 --- a/selective.cabal +++ b/selective.cabal @@ -36,7 +36,8 @@ library hs-source-dirs: src exposed-modules: Control.Selective, Control.Selective.Free, - Control.Selective.Free.Rigid + Control.Selective.Rigid.Free, + Control.Selective.Rigid.Freer build-depends: base >= 4.7 && < 5, containers >= 0.5.5.1 && < 0.7, transformers >= 0.4.2.0 && < 0.6 @@ -59,8 +60,6 @@ library test-suite test hs-source-dirs: test, examples other-modules: Build, - FreerRigid, - FasterFreerRigid, Laws, Parser, Processor, diff --git a/src/Control/Selective/Free/Rigid.hs b/src/Control/Selective/Rigid/Free.hs similarity index 95% rename from src/Control/Selective/Free/Rigid.hs rename to src/Control/Selective/Rigid/Free.hs index 19beb7c..a0e71e2 100644 --- a/src/Control/Selective/Free/Rigid.hs +++ b/src/Control/Selective/Rigid/Free.hs @@ -1,7 +1,7 @@ {-# LANGUAGE GADTs, RankNTypes, TupleSections #-} ----------------------------------------------------------------------------- -- | --- Module : Control.Selective.Free.Rigid +-- Module : Control.Selective.Rigid.Free -- Copyright : (c) Andrey Mokhov 2018-2019 -- License : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com @@ -12,11 +12,11 @@ -- and monads, introduced in this paper: -- https://www.staff.ncl.ac.uk/andrey.mokhov/selective-functors.pdf. -- --- This module defines /free rigid selective functors/, i.e. for selective --- functors satisfying the property @\<*\> = apS@. +-- This module defines /free rigid selective functors/. Rigid selective functors +-- are those that satisfy the property @\<*\> = apS@. -- ----------------------------------------------------------------------------- -module Control.Selective.Free.Rigid ( +module Control.Selective.Rigid.Free ( -- * Free rigid selective functors Select (..), liftSelect, diff --git a/test/FreerRigid.hs b/src/Control/Selective/Rigid/Freer.hs similarity index 76% rename from test/FreerRigid.hs rename to src/Control/Selective/Rigid/Freer.hs index 47544bb..c9413f9 100644 --- a/test/FreerRigid.hs +++ b/src/Control/Selective/Rigid/Freer.hs @@ -1,5 +1,24 @@ {-# LANGUAGE DeriveFunctor, GADTs, RankNTypes #-} -module FreerRigid ( +----------------------------------------------------------------------------- +-- | +-- Module : Control.Selective.Rigid.Freer +-- Copyright : (c) Andrey Mokhov 2018-2019 +-- License : MIT (see the file LICENSE) +-- Maintainer : andrey.mokhov@gmail.com +-- Stability : experimental +-- +-- This is a library for /selective applicative functors/, or just +-- /selective functors/ for short, an abstraction between applicative functors +-- and monads, introduced in this paper: +-- https://www.staff.ncl.ac.uk/andrey.mokhov/selective-functors.pdf. +-- +-- This module defines /freer rigid selective functors/. Rigid selective +-- functors are those that satisfy the property @\<*\> = apS@. Compared to the +-- "free" construction from "Control.Selective.Rigid.Free", this "freer" +-- construction does not require the underlying base data type to be a functor. +-- +----------------------------------------------------------------------------- +module Control.Selective.Rigid.Freer ( -- * Free rigid selective functors Select (..), liftSelect, diff --git a/test/FasterFreerRigid.hs b/test/FasterFreerRigid.hs deleted file mode 100644 index 76e6a07..0000000 --- a/test/FasterFreerRigid.hs +++ /dev/null @@ -1,82 +0,0 @@ -{-# LANGUAGE DeriveFunctor, GADTs, RankNTypes #-} -module FasterFreerRigid ( - -- * Free rigid selective functors - Select (..), liftSelect, - - -- * Static analysis - getPure, getEffects, getNecessaryEffect, runSelect, foldSelect - ) where - -import Control.Monad.Trans.Except -import Control.Selective -import Data.Bifunctor -import Data.Function -import Data.Functor - --- Inspired by free applicative functors by Capriotti and Kaposi. --- See: https://arxiv.org/pdf/1403.0749.pdf - --- Note: In the current implementation, 'select' costs O(N), where N is the --- number of effects. It is possible to improve this to O(1) by using the idea --- developed for free applicative functors by Dave Menendez, see this blog post: --- https://www.eyrie.org/~zednenem/2013/05/27/freeapp --- An example implementation can be found here: --- http://hackage.haskell.org/package/free/docs/Control-Applicative-Free-Fast.html - --- | Free rigid selective functors. -data Select f a where - Pure :: a -> Select f a - Select :: (a -> Either (b -> c) c) -> Select f a -> f b -> Select f c - --- TODO: Prove that this is a lawful 'Functor'. -instance Functor (Select f) where - fmap f (Pure a) = Pure (f a) - fmap f (Select g x y) = Select (bimap (f.) f <$> g) x y -- O(1) - --- TODO: Prove that this is a lawful 'Applicative'. -instance Applicative (Select f) where - pure = Pure - (<*>) = apS -- Rigid selective functors - --- TODO: Prove that this is a lawful 'Selective'. -instance Selective (Select f) where - select = selectBy (first (&)) - where - selectBy :: (a -> Either (b -> c) c) -> Select f a -> Select f b -> Select f c - selectBy f x (Pure y) = either ($y) id . f <$> x - selectBy f x (Select g y z) = Select id (selectBy h x y) z -- O(N) - where - h a = case f a of Right r -> Right (Right r) - Left dr -> Left (bimap (dr.) dr . g) - --- | Lift a functor into a free selective computation. -liftSelect :: f a -> Select f a -liftSelect f = Select (const $ Left id) (Pure ()) f - --- | Given a natural transformation from @f@ to @g@, this gives a canonical --- natural transformation from @Select f@ to @g@. -runSelect :: Selective g => (forall x. f x -> g x) -> Select f a -> g a -runSelect _ (Pure a) = pure a -runSelect t (Select f x y) = select (f <$> runSelect t x) ((&) <$> t y) - --- | Concatenate all effects of a free selective computation. -foldSelect :: Monoid m => (forall x. f x -> m) -> Select f a -> m -foldSelect f = getOver . runSelect (Over . f) - --- | Extract the resulting value if there are no necessary effects. -getPure :: Select f a -> Maybe a -getPure = runSelect (const Nothing) - --- | Collect all possible effects in the order they appear in a free selective --- computation. -getEffects :: Functor f => Select f a -> [f ()] -getEffects = foldSelect (pure . void) - --- | Extract the necessary effect from a free selective computation. Note: there --- can be at most one effect that is statically guaranteed to be necessary. -getNecessaryEffect :: Functor f => Select f a -> Maybe (f ()) -getNecessaryEffect = leftToMaybe . runExcept . runSelect (throwE . void) - -leftToMaybe :: Either a b -> Maybe a -leftToMaybe (Left a) = Just a -leftToMaybe _ = Nothing diff --git a/test/Main.hs b/test/Main.hs index 808cfe2..e6c858f 100644 --- a/test/Main.hs +++ b/test/Main.hs @@ -14,7 +14,7 @@ import Laws import Validation import qualified Control.Selective.Free as F -import qualified Control.Selective.Free.Rigid as FR +import qualified Control.Selective.Rigid.Free as FR import qualified Teletype as F import qualified Teletype.Rigid as FR