How to implement Monadic instance of a "finally tagless" typeclass in PureScript? - dsl

I'm working on implementing an embedded DSL in PureScript using the "finally tagless" style. The repo can be found at https://github.com/afcondon/purescript-finally-tagless-ex
Here's the problem. Given an abstract definition of a very simplified file system:
class (Monad m) <= MonadFileSystem m where
cd :: FilePath -> m Unit
ls :: m (Array (Tuple FilePath FileType))
cat :: Array FilePath -> m String
One can easily provide an implementation such as this one (https://github.com/afcondon/purescript-finally-tagless-ex/blob/master/MonadicEx/src/FakeFileSystem.purs) which can be used as an embedded language and interpreted (or run) to evaluate as a string (alternatively you could do static analysis on the structure instead of turning it into a string).
In principle, one can also have a side-effecting example which would actually interact with a file system but which could "interpret" exactly the same embedded language. I'd like to use purescript-node-fs for this which would mean accepting Eff (fs :: FS, err :: EXCEPTION | eff) somewhere.
My question is - how does one actually implement the "real", effectful instance? do you have to change the signatures of cd, ls and cat? or can you somehow evaluate the whole monad in Eff such that those functions do not need to carry the Eff in their signature?

Because you want to make an instance for Eff, there's a little problem here since we need to include the row in the type, but as you probably found, the compiler complains about the instance head in that case.
One option is to use a newtype:
import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Exception (EXCEPTION)
import Data.Tuple (Tuple)
import Node.FS (FS)
import Node.Path (FilePath)
type FileType = String
class (Monad m) <= MonadFileSystem m where
cd :: FilePath -> m Unit
ls :: m (Array (Tuple FilePath FileType))
cat :: Array FilePath -> m String
newtype FSEff eff a = FSEff (Eff (fs :: FS, err :: EXCEPTION | eff) a)
runFSEff :: forall eff a. FSEff eff a -> Eff (fs :: FS, err :: EXCEPTION | eff) a
runFSEff (FSEff fse) = fse
derive newtype instance functorFSEff :: Functor (FSEff eff)
derive newtype instance applyFSEff :: Apply (FSEff eff)
derive newtype instance applicativeFSEff :: Applicative (FSEff eff)
derive newtype instance bindFSEff :: Bind (FSEff eff)
derive newtype instance monadFSEff :: Monad (FSEff eff)
instance monadFileSystemFSEff :: MonadFileSystem (FSEff eff) where
cd _ = pure unit
ls = pure []
cat _ = pure "meow"
But there is also some trickery that can be done using functional dependencies, where you can specify the row like an equality constraint instead. This compiles, but I've not tried using this technique for real yet, so I can't vouch for it definitely working in a larger context:
import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Exception (EXCEPTION)
import Data.Tuple (Tuple)
import Node.FS (FS)
import Node.Path (FilePath)
type FileType = String
class (Monad m) <= MonadFileSystem m where
cd :: FilePath -> m Unit
ls :: m (Array (Tuple FilePath FileType))
cat :: Array FilePath -> m String
instance monadFileSystemEff :: EffectRowEquals r (fs :: FS, err :: EXCEPTION | eff) => MonadFileSystem (Eff r) where
cd _ = pure unit
ls = pure []
cat _ = pure "meow"
-- This should probably go in `purescript-type-equality`:
class EffectRowEquals (a ∷ # !) (b ∷ # !) | a → b, b → a where
toER ∷ ∀ r. r a → r b
fromER ∷ ∀ r. r b → r a
instance reflER ∷ EffectRowEquals r r where
toER er = er
fromER er = er

Related

Using >> without explicitly declaring it in a monad

I am trying to get good at Monads and have written the following Monads and functions in which I use the >> (in the apply-function) although it is not declared in the Monad itself. How come this is possible to compile, as I understand http://learnyouahaskell.com/a-fistful-of-monads#walk-the-line it is required to declare it in the instantiation of the Monad as is the case with the Maybe Monad.
data Value =
NoneVal
| TrueVal | FalseVal
| IntVal Int
| StringVal String
| ListVal [Value]
deriving (Eq, Show, Read)
data RunErr = EBadV VName | EBadF FName | EBadA String
deriving (Eq, Show)
newtype CMonad a = CMonad {runCMonad :: Env -> (Either RunErr a, [String]) }
instance Monad CMonad where
return a = CMonad (\_ -> (Right a, []))
m >>= f = CMonad (\env -> case runCMonad m env of
(Left a, strLst) -> (Left a, strLst)
(Right a, strLst) -> let (a', strLst') = runCMonad (f a) env in (a', strLst ++ strLst'))
output :: String -> CMonad ()
output s = CMonad(\env -> (Right (), [] ++ [s]))
apply :: FName -> [Value] -> CMonad Value
apply "print" [] = output "" >> return NoneVal
Furthermore, how would I make it possible to show the output (print it) from the console when running apply. Currently I get the following error message, although my types have derive Show:
<interactive>:77:1: error:
* No instance for (Show (CMonad Value)) arising from a use of `print'
* In a stmt of an interactive GHCi command: print it
The >> operator is optional, not required. The documentation states that the minimal complete definition is >>=. While you can implement both >> and return, you don't have to. If you don't supply them, Haskell can use default implementations that are derived from either >> and/or Applicative's pure.
The type class definition is (current GHC source code, reduced to essentials):
class Applicative m => Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k
return :: a -> m a
return = pure
Notice that >>= lacks an implementation, which means that you must supply it. The two other functions have a default implementation, but you can 'override' them if you want to.
If you want to see output from GHCi, the type must be a Show instance. If the type wraps a function, there's no clear way to do that.
The declaration of Monad in the standard Prelude is as follows: (simplified from the Prelude source)
class Applicative m => Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k
{-# INLINE (>>) #-}
return :: a -> m a
return = pure
It's a typeclass with three methods, (>>=), (>>) and return.
Of those three, two have a default implementation - the function is implemented in the typeclass, and one does not.
Monad is a subclass of Applicative, and return is the same as pure - it is included in the Monad typeclass (or at all) for historical reasons.
Of the remaining two, (>>=) is all that is needed to define a Monad in Haskell. (>>) could be defined outside of the typeclass, like this:
(>>) :: (Monad m) => forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k
The reason this is included is in case a monad author wants to override the default implementation with an implementation which is more efficient.
A typeclass method which is not required is know as optional.
Haddock documentation automatically generates a 'Mnimal complete definition' based on the methods without default implementations. You can see here that the minimal definition of Monad is indeed (>>=).
Sometimes, all methods can have default implementations, but they are not optional. This can happen when one of two methods must be provided, and the other is defined in terms of it. This is the case for the Traversable typeclass, where traverse and sequenceA are both implemented in terms of each other. Not implementing either method will cause them to go into an infinite loop.
To let you mark this, GHC provides the MINIMAL pragma, which generates the neccesary compiler warnings, and ensures the Haddocks are correct.
As an aside, failing to implement a required typeclass method is by default a compiler warning, not an error, and will cause a runtime exception if called. There is no good reason for this behaviour.
You can change this default using the -Werror=missing-methods GHC flag.
Happy Haskelling!

What's the use case for the MonadReader instance for (->) r

I find the MonadReader instance for (->) r difficult to understand.
Someone from irc mentions one use case for extending some polymorphic functions found in other people's package. I couldn't recall exactly what he meant. Here's an example that relates to what he said but I don't see the point. Could anyone give another example on the usecase of MonadReader for (->) r
func :: (Show a, MonadReader Int m) => Bool -> m a
func b = case b of
True -> do
i <- ask
show i
False -> "error"
main :: IO ()
main = print $ func True 5
The point is to make it easier to combine functions that all take the same environment.
Consider the type a -> Env -> b, where Env is some data type that contains all your "global" variables. Let's say you wanted to compose two such functions. You can't just write h = f2 . f1, because f1's return type Env -> b doesn't match f2's argument type b.
f1 :: a -> Env -> b -- a -> ((->) Env b)
f2 :: b -> Env -> c -- b -> ((->) Env c)
h :: a -> Env -> c
h x e = let v = f1 x e
in f2 v e
Because there is an applicable MonadReader instance for the monad (->) Env, you can write this as
-- The class, ignoring default method implementations, is
-- class Monad m => MonadReader r m | m -> r where
-- ask :: m r
-- local :: (r -> r) -> m a -> m a
-- reader :: (r -> a) -> m a
--
-- The functional dependency means that if you try to use (->) Env
-- as the monad, Env is forced to be the type bound to r.
--
-- instance MonadReader r ((->) r) where
-- ask = id
-- local f m = m . f
-- reader = id
h :: MonadReader Env m => a -> m c
h x = do
v <- f1 x
f2 v
-- h x = f1 x >>= f2
without explicit reference to the environment, which h doesn't
care about; only f1 and f2 do.
More simply, you can use the Kleisli composition operator to define the same function.
import Control.Monad
h :: MonadReader Env m => a -> m c
h = f1 >=> f2
In your example, ask is simply how you get access to the environment from inside the body of the function, rather than having it as a preexisting argument to the function. Without the MonadReader instance, you would write something like
func :: Show a => Bool -> Int -> a -- m ~ (->) Int
func b i = case b of
True -> show i
False -> error "nope"
The definition of main stays the same. However, (->) Int isn't the only type that has a MonadReader instance; there could be a more complicated monad stack
that you are using elsewhere, which the more general type (Show a, MonadReader Int m) => Bool -> m a allows you to use instead of "just" (->) Int.
I'm not sure it was intended to have a use case separate from the Reader monad.
Here's some of the history...
The inspiration for the transformers library was the set of lecture notes Functional Programming with Overloading and Higher-Order Polymorphism (Mark P. Jones, 1995). In these notes, several named monads (State, Id, List, Maybe, Error, and Writer) were discussed. For example, the Writer monad type and its instance were defined as:
data Writer a = Result String a
instance Monad Writer where
result x = Result "" x
Result s x ‘bind‘ f = Result (s ++ s’) y
where Result s’ y = f x
The reader monad was also discussed, but it wasn't defined as a separate type. Rather a Read type alias was used together with a Monad instance defined directly in terms of the partially applied function type (->) r:
type Read r = (r ->)
instance Monad (r->) where
result x = \r -> x
x ‘bind‘ f = \r -> f (x r) r
I don't actually know if these type-level "sections" (r ->) were valid Haskell syntax at the time. Anyway, it's not valid syntax with modern GHC versions, but that's how it appeared in the notes.
The first version of the transformers library authored by Andy Gill -- or at least the first that I was able to find, and it was actually still part of the base library at that time -- was checked into Git in June, 2001. It introduced the MonadReader class and the newtype wrapped Reader:
newtype Reader r a = Reader { runReader :: r -> a }
together with its Functor, Monad, MonadFix, and MonadReader instances. (No Applicative -- that hadn't been invented yet.) It also included a set of instances for (->) r with the comment:
The partially applied function type is a simple reader monad
So, I think the original formulation in the lecture notes led Andy to include these instances for (->) r, even though he also introduced a dedicated Reader newtype for consistency with the other monads in the transformers library.
Anyway, that's the history. As for use cases, I can only think of one serious one, though perhaps it isn't that compelling. The lens library is designed to interface well with MonadState and MonadReader to access complex states/contexts. Because functions like:
view :: MonadReader s m => Getting a s a -> m a
preview :: MonadReader s m => Getting (First a) s a -> m (Maybe a)
review :: MonadReader b m => AReview t b -> m t
are defined in terms of the MonadReader instance, they can be used both in a traditional Reader context:
do ...
outdir <- view (config.directories.output)
...
and in a plain function context:
map (view (links.parent.left)) treeStructure
Again, not necessarily a compelling use case, but it's a use case.

Why is FunctionalDependency needed for defining MonadReader?

I just managed to understand the definition of the class MonadReader
class Monad m => MonadReader r m | m -> r where
...
After reading the document of Functional Dependency in Haskell, now I can understand that | m -> r specifies that type variable r is uniquely decided by m. I think this requirement is reasonable based on the few typical instances of MonadReader I have seen so far (e.g. Reader), but it seems to me that we can still define instances like Reader even without this functional dependency clause.
My question is why we need functional dependency in the definition of MonadReader? Is this functionally necessary for defining MonadReader in a sense that MonadReader cannot be properly defined without it, or it is merely a restriction to limit the ways how MonadReader can be used so that the instances of MonadReader will all behave in a certain expected way?
It is needed to make type inference work in a way which is more convenient to the user.
For example, without the fundep this would not compile:
action :: ReaderT Int IO ()
action = do
x <- ask
liftIO $ print x
To make the above compile we would need to write
action :: ReadertT Int IO ()
action = do
x <- ask :: ReadertT Int IO Int
liftIO $ print x
This is because, without the fundep, the compiler can not infer that x is an Int. After all a monad ReadertT Int IO might have multiple instances
instance MonadReader Int (ReaderT Int IO) where
ask = ReaderT (\i -> return i)
instance MonadReader Bool (ReaderT Int IO) where
ask = ReaderT (\i -> return (i != 0))
instance MonadReader String (ReaderT Int IO) where
ask = ReaderT (\i -> return (show i))
-- etc.
so the programmer must provide some annotation which forces x :: Int, or the code is ambiguous.
This is not really an answer, but it's much too long for a comment. You are correct that it's possible to define the MonadReader class without a fundep. In particular, the type signature of each method determines every class parameter. It would be quite possible to define a finer hierarchy.
class MonadReaderA r m where
askA :: m r
askA = readerA id
readerA :: (r -> a) -> m a
readerA f = f <$> askA
-- This effect is somewhat different in
-- character and requires special lifting.
class MonadReaderA r m => MonadReaderB r m where
localB :: (r -> r) -> m a -> m a
class MonadReaderB r m
=> MonadReader r m | m -> r
ask :: MonadReader r m => m r
ask = askA
reader
:: MonadReader r m
=> (r -> a) -> m a
reader = readerA
local
:: MonadReader r m
=> (r -> r) -> m a -> m a
local = localB
The main problem with this approach is that users have to write a bunch of instances.
I think the source of confusion is that in the definition of
class Monad m => MonadReader r m | m -> r where
{- ... -}
It is implicitly asumed that m contains r itself (for common instances). Let me use a lighter definiton of Reader as
newtype Reader r a = Reader {runReader :: r -> a}
When the r parameter is chosen you can easely define a monad instance for Reader r. That means that in the type class definition m should be substitute for Reader r. So take a look at how the expresion ends up being:
instance MonadReader r (Reader r) where -- hey!! r is duplicated now
{- ... -} -- The functional dependecy becomes Reader r -> r which makes sense
But why do we need this?. Look at the definition of ask within the MonadReader class.
class Monad m => MonadReader r m | m -> r where
ask :: m r -- r and m are polymorphic here
{- ... -}
Without the fun-dep nothing could stop me for defining ask in a way to return a different type as the state. Even more, I could define many instances of monad reader for my type. As an example, this would be valid definitions without func-dep
instance MonadReader Bool (Reader r) where
-- ^^^^ ^
-- | |- This is state type in the user defined newtype
-- |- this is the state type in the type class definition
ask :: Reader r Bool
ask = Reader (\_ -> True) -- the function that returns True constantly
{- ... -}
instance MonadReader String (Reader r) where
-- ^^^^^^ ^
-- | |- This is read-state type in the user defined newtype
-- |- this is the read-state type in the type class definition
ask :: Reader r String
ask = Reader (\_ -> "ThisIsBroken") -- the function that returns "ThisIsBroken" constantly
{- ... -}
So if I had a value val :: ReaderT Int IO Double what would be the result of ask. We'd need to specify a type signature as below
val :: Reader Int Double
val = do
r <- ask :: Reader Int String
liftIO $ putStrLn r -- Just imagine you can use liftIO
return 1.0
> val `runReader` 1
"ThisIsBroken"
1.0
val :: Reader Int Double
val = do
r <- ask :: Reader Int Bool
liftIO $ print r -- Just imagine you can use liftIO
return 1.0
> val `runReader` 1
True
1.0
Aside from being senseless, it is unconvinient to be specifiying the type over and over.
As a conclusion using the actual definition of ReaderT. When you have something like val :: ReaderT String IO Int the functional dependency says Such a type might have only one single instance of MonadReader typeclass which is defined to be the one that uses String as r

Can the type of this function be declared in standard Haskell

The following program compiles under GHC 8.0.2 with no language extensions, and produces the expected two lines of output.
However, it does not compile if the (non-top-level) type declaration for the value write' is removed.
Also, I cannot find any (top-level) type declaration for the function write.
I find this rather odd. If this is acceptable standard Haskell, surely it should be possible to create a type declaration for the function write.
So my question is: is there such a type declaration?
import Control.Monad.Trans.Maybe (MaybeT, runMaybeT)
import Control.Monad.Writer (MonadTrans, Writer, lift, runWriter, tell, when)
import ListT (ListT, toList) -- Volkov's list-t package
logging = True
write x = when logging write' where
write' :: MonadTrans m => m (Writer [String]) ()
write' = lift $ tell [x]
f :: ListT (Writer [String]) String
f = do
write "Hello from f"
return "ABC"
g :: MaybeT (Writer [String]) Int
g = do
write "Hello from g"
return 123
main :: IO ()
main = do
print $ runWriter $ toList f
print $ runWriter $ runMaybeT g
Using GHCi (remember to put this into a separate file and load it on GHCi's command line lest you get confused by GHCi's altered typing rules):
> :t write
write :: (Applicative (m (Writer [String])), MonadTrans m) =>
String -> m (Writer [String]) ()
Why? Well,
write' :: MonadTrans m => m (Writer [String]) ()
when :: Applicative f => Bool -> f () -> f ()
when logging :: Applicative f => f () -> f ()
so, when logging write' must unify write''s m (Writer [String]) with when loggings's f, causing the combined constraint (Applicative (m (Writer [String])), MonadTrans m). But wait, let's remove the type signatures and see what the most general type is:
-- equivalent but slightly easier to talk about
write = when logging . lift . tell . (:[])
(:[]) :: a -> [a]
tell :: MonadWriter w m -> w -> m ()
lift :: (Monad m, MonadTrans t) => m a -> t m a
tell . (:[]) :: MonadWriter [a] m => a -> m ()
lift . tell . (:[]) :: (MonadWriter [a] m, MonadTrans t) => a -> t m ()
when logging . lift . tell . (:[]) = write
:: (Applicative (t m), MonadWriter [a] m, MonadTrans t) => a -> t m ()
-- GHCi agrees
Per se, there's nothing wrong with this type. However, standard Haskell does not allow this. In standard Haskell, a constraint must be of the form C v or C (v t1 t2 ...) where v is a type variable. In the compiling case, this holds: the Applicative constraint has the type variable m on the outside, and the MonadTrans is just m. This is true in the non-compiling version, too, but we also have the constraint MonadWriter ([] a) m. [] is no type variable, so the type here is rejected. This constraint arises in the compiling version, too, but the type signatures nail the variables down to produce MonadWriter [String] (Writer [String]), which is immediately satisfied and does not need to appear in the context of write.
The restriction is lifted by enabling FlexibleContexts (preferably via a {-# LANGUAGE FlexibleContexts #-} pragma, but also maybe by -XFlexibleContexts). It originally existed to prevent things such as the following:
class C a where c :: a -> a
-- no instance C Int
foo :: C Int => Int
foo = c (5 :: Int)
-- with NoFlexibleContexts: foo's definition is in error
-- with FlexibleContexts: foo is fine; all usages of foo are in error for
-- not providing C Int. This might obscure the source of the problem.
-- slightly more insiduous
data Odd a = Odd a
-- no Eq (Odd a)
oddly (Odd 0) (Odd 0) = False
oddly l r = l == r
-- oddly :: (Num a, Eq (Odd a), Eq a) => Odd a -> Odd a -> Bool
-- Now the weird type is inferred! With FlexibleContexts,
-- the weird constraint can propagate quite far, causing errors in distant
-- places. This is confusing. NoFlexibleContexts places oddly in the spotlight.
But it happens to get in the way a lot when you have MultiParamTypeClasses on.

Build more advanced generic parser

ok, here is a continuation of my previous question (Generically) Build Parsers from custom data types?. I took the advice and decided to build my parsers with generic-sop and all was going fine until now.
I need to expand my implementation a little bit so more complicated situations can be dealt with. Namely, consider these two data definitions, where B is built on top of A:
data A = A String Int
data B = B A Double
In order to generically parse all data structures, I define the following class:
class HasSimpleParser f where
getSimpleParser :: Parser f
class Parsable f where
getParser :: Parser f
class GenericallyParsable f where
getGenericParser :: Parser f
The primitive types such as Int, String, Double etc can be made into instances of HasSimpleParser easily. Then I make data structure such as A an instance of Parsable by doing
instance (Generic r, Code r ~ '[xs], All HasSimpleParser xs) => Parsable r where
getParser = to . SOP. Z <$> hsequence (hcpure (Proxy #HasSimpleParser) getSimpleParser)
I introduce the class GenericallyParsable to parse data structure like B. So I do the following:
instance (Generic r, Code r ~ '[xs], All Parsable xs) => GenericallyParsable r where
getGenericParser = to . SOP. Z <$> hsequence (hcpure (Proxy #Parsable) getParser)
The last pieces of the puzzle are the parsing functions:
parseA :: InputStream ByteString -> IO A
parseA = parseFromStream (getGenericParser #A)
parseB :: InputStream ByteString -> IO B
parseB = parseFromStream (getGenericParser #B)
However, the code won't compile and I got the following error:
• Couldn't match type ‘'['[Char, [Char]]]’ with ‘'[]’
arising from a use of ‘getGenericParser’
• In the first argument of ‘parseFromStream’, namely
‘(getGenericParser #A)’
In the expression: parseFromStream (getGenericParser #A)
In an equation for ‘parseA’:
parseA = parseFromStream (getGenericParser #A)
So how should I modify the code to work?
I think the GenericallyParsable typeclass is not necessary.
Just define a HasSimpleParser instance for A that piggybacks on Parsable:
instance HasSimpleParser A where
getSimpleParser = getParser
If you end up declaring many instances of this type for your records, you can streamline it a little using {-# language DefaultSignatures #-} and changing the definition of HasSimpleParser to
class HasSimpleParser c where
getSimpleParser :: Parser c
default getSimpleParser :: Parsable c => Parser c
getSimpleParser = getParser
Now in the record instances you would only have to write:
instance HasSimpleParser A
In fact, perhaps even the distinction between HasSimpleParser and Parsable in unnecessary. A single HasParser typeclass with instances for both basic and composite types would be enough. The default implementation would use generics-sop and require a (Generic r, Code r ~ '[xs], All HasParser xs) constraint.
class HasParser c where
getParser :: Parser c
default getParser :: (Generic c, Code c ~ '[xs], All HasParser xs) => Parser c
getParser = ...generics-sop code here...

Resources