Comments (4)
Current Alternative instance for Free is giving un-intuitive result.
While interpreting ((getLn *> pure ()) <|> putLn "Actual: This should get printed")
, I would expect
putLn
to interpreted when there is failure in interpreting getLn
. To get the behaviour I want, I had to re-define (<|>) for Free similar to the one above.
Is there a problem in defining Alternative instance for Free in a way that is being done in the following code?
#!/usr/bin/env stack
{- stack
script
--resolver nightly-2017-09-07
--package free
-}
{-# LANGUAGE DeriveFunctor #-}
module Main where
import Control.Monad.Free as FreeM
import Control.Alternative.Free as FreeA
import Control.Applicative
data ActF f
= GetLine (String -> f)
| PutLine String f
deriving (Functor)
type Action a = Free (Alt ActF) a
getLn :: Action String
getLn = liftF $ liftAlt $ GetLine id
putLn :: String -> Action ()
putLn s = liftF $ liftAlt $ PutLine s ()
run p = foldFree foldAlts p
foldAlts as = runAlt interpret as
interpret (PutLine s f) = putStrLn s >> (pure f)
interpret (GetLine f) = ioError $ userError "getline failed"
(<||>) :: (Alternative f) => Free f a -> Free f a -> Free f a
(<||>) (FreeM.Pure alt1) _ = pure alt1
(<||>) (Free alt1) a2@(FreeM.Pure alt2) = FreeM.Free (alt1 <|> pure a2)
(<||>) (Free alt1) (Free alt2) = FreeM.Free (alt1 <|> alt2)
infixl 3 <||>
actualCase = ((getLn *> pure ()) <|> putLn "Actual: This should get printed")
expectedCase = ((getLn *> pure ()) <||> putLn "Expected: This should get printed")
main = do
run expectedCase
run actualCase
$./FreeAlt.hs
Expected: This should get printed
FreeAlt.hs: user error (mzero)
from free.
I too wonder if @michaelt's instance is sane. Here's a use-case: "upgrading" the async Concurrently
applicative to a monad, while inheriting its concurrent applicative and alternative behaviors.
import Control.Alternative.Free (Alt, liftAlt, runAlt)
import Control.Concurrent.Async (Concurrently(..))
import Control.Monad.Free.Ap -- Not quite, need the alternative Alternative instance
newtype Conc a
= Conc { unConc :: Free (Alt Concurrently) a }
deriving (Functor, Applicative, Alternative, Monad)
instance MonadIO Conc where
liftIO = Conc . liftF . liftAlt . Concurrently
await :: Conc a -> IO a
await = foldFree (runConcurrently . runAlt id) . unConc
For example, this would run f1
, then f2
, f3
and f4
in parallel, using whichever of f2
and f3
finish first:
foo :: IO Int
foo =
await $ do
i <- f1
(j, k) <- liftA2 (,) (f2 <|> f3) f4
pure (i + j + k)
EDIT: Oops, I realized today that this example doesn't need the free Alternative at all. But, it would still benefit from the alternate Alternative instance for Free.
from free.
The proposed instance, and its extension to FreeT
, certainly seem much more useful than the ones currently used for either Free
or FreeT
. My only major question is whether there's a good way to implement this for Control.Monad.Trans.Free.Church
. Also, whether there's a good way to implement this for other "final" free monad transformer definitions like
type f ~> g = forall x. f x -> g x
newtype FF f m a = FF
{ runFF :: forall n. Monad n
=> (f ~> n) -- Any natural transformation
-> (m ~> n) -- A monad morphism
-> n a }
Maybe one of you wizards can find good approaches.
from free.
Note to email followers: my last comment has been edited.
from free.
Related Issues (20)
- Metadata revisions for 4.8 and 4.8.0.1 HOT 2
- free-5 doesn't build on old GHCs with transformers-0.4 HOT 3
- Fails with GHC-7.8.4 and installed transformers HOT 9
- Failure building free 5.0.2 with GHC 8.4.2 cross to iOS
- 'Ap' from 'Control.Applicative.Free' conflicts with 'Ap' in base-4.12
- ComonadTraced instance for CofreeT
- Add a MonadBaseControl instance for CofreeT HOT 6
- Simplify the applicative instance of Free HOT 2
- Deriving Via for several datatypes HOT 1
- Comonad f => MonadFree f (Tagged f) HOT 1
- Nu-based distributive cofree
- Add a class for free monad transformer-type things.
- Document 'Control.Monad.Free.Ap' has to work only on "commutative" monads
- Why does hoistFree have such a strict type? HOT 2
- deriving (Applicative, Monad) via GenericFreeMonad "Pure" (Free f)
- Support transformers-0.6 HOT 3
- Further simplify instances to avoid overkill *1 classes
- Dangling Links HOT 2
- `hoistFree` should be named `transFree`
- MonadAccum instance
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from free.