Purescript Union of Rows - typeclass

I've been trying to develop a component system in Purescript, using a Component typeclass which specifies an eval function. The eval function for can be recursively called by a component for each sub-component of the component, in essence fetching the input's values.
As components may wish to use run-time values, a record is also passed into eval. My goal is for the rows in the Record argument of the top-level eval to be required to include all the rows of every sub-component. This is not too difficult for components which do not use any rows themselves, but their single sub-component does, as we can simply pass along the sub-components rows to the component's. This is shown in evalIncrement.
import Prelude ((+), one)
import Data.Symbol (class IsSymbol, SProxy(..))
import Record (get)
import Prim.Row (class Cons, class Union)
class Component a b c | a -> b where
eval :: a -> Record c -> b
data Const a = Const a
instance evalConst :: Component (Const a) a r where
eval (Const v) r = v
data Var (a::Symbol) (b::Type) = Var
instance evalVar ::
( IsSymbol a
, Cons a b r' r) => Component (Var a b) b r where
eval _ r = get (SProxy :: SProxy a) r
data Inc a = Inc a
instance evalInc ::
( Component a Int r
) => Component (Inc a) Int r where
eval (Inc a) r = (eval a r) + one
All of the above code works correctly. However, once I try to introduce a component which takes multiple input components and merges their rows, I cannot seem to get it to work. For example, when trying to use the class Union from Prim.Row:
data Add a b = Add a b
instance evalAdd ::
( Component a Int r1
, Component b Int r2
, Union r1 r2 r3
) => Component (Add a b) Int r3 where
eval (Add a b) r = (eval a r) + (eval b r)
The following error is produced:
No type class instance was found for
Processor.Component a3
Int
r35
while applying a function eval
of type Component t0 t1 t2 => t0 -> { | t2 } -> t1
to argument a
while inferring the type of eval a
in value declaration evalAdd
where a3 is a rigid type variable
r35 is a rigid type variable
t0 is an unknown type
t1 is an unknown type
t2 is an unknown type
In fact, even modifying the evalInc instance to use a dummy Union with an empty row produces a similar error, like so:
instance evalInc :: (Component a Int r, Union r () r1)
=> Component (Increment a) Int r1 where
Am I using Union incorrectly? Or do I need further functional dependencies for my class - I do not understand them very well.
I am using purs version 0.12.0

r ∷ r3 but it is being used where an r1 and r2 are required, so there is a type mismatch. A record {a ∷ A, b ∷ B} cannot be given where {a ∷ A} or {b ∷ B} or {} is expected. However, one can say this:
f ∷ ∀ s r. Row.Cons "a" A s r ⇒ Record r → A
f {a} = a
In words, f is a function polymorphic on any record containing a label "a" with type A. Similarly, you could change eval to:
eval ∷ ∀ s r. Row.Union c s r ⇒ a → Record r → b
In words, eval is polymorphic on any record which contains at least the fields of c. This introduces a type ambiguity which you will have to resolve with a proxy.
eval ∷ ∀ proxy s r. Row.Union c s r ⇒ proxy c → a → Record r → b
The eval instance of Add becomes:
instance evalAdd ∷
( Component a Int r1
, Component b Int r2
, Union r1 s1 r3
, Union r2 s2 r3
) => Component (Add a b) Int r3 where
eval _ (Add a b) r = eval (RProxy ∷ RProxy r1) a r + eval (RProxy ∷ RProxy r2) b r
From here, r1 and r2 become ambiguous because they're not determined from r3 alone. With the given constraints, s1 and s2 would also have to be known. Possibly there is a functional dependency you could add. I am not sure what is appropriate because I am not sure what the objectives are of the program you are designing.

As the instance for Var is already polymorphic (or technically open?) due to the use of Row.Cons, ie
eval (Var :: Var "a" Int) :: forall r. { "a" :: Int | r } -> Int
Then all we have to is use the same record for the left and right evaluation, and the type system can infer the combination of the two without requiring a union:
instance evalAdd ::
( Component a Int r
, Component b Int r
) => Component (Add a b) Int r where
eval (Add a b) r = (eval a r) + (eval b r)
This is more obvious when not using typeclasses:
> f r = r.foo :: Int
> g r = r.bar :: Int
> :t f
forall r. { foo :: Int | r } -> Int
> :t g
forall r. { bar :: Int | r } -> Int
> fg r = (f r) + (g r)
> :t fg
forall r. { foo :: Int, bar :: Int | r } -> Int
I think the downside to this approach compared to #erisco's is that the open row must be in the definition of instances like Var, rather than in the definition of eval? It is also not enforced, so if a Component doesn't use open rows then a combinator such as Add no longer works.
The benefit is the lack of the requirement for the RProxies, unless they are not actually needed for eriscos implementation, I haven't checked.
Update:
I worked out a way of requiring eval instances to be closed, but it makes it quite ugly, making use of pick from purescript-record-extra.
I'm not really sure why this would be better over the above option, feels like I'm just re-implementing row polymorphism
import Record.Extra (pick, class Keys)
...
instance evalVar ::
( IsSymbol a
, Row.Cons a b () r
) => Component (Var a b) b r where
eval _ r = R.get (SProxy :: SProxy a) r
data Add a b = Add a b
evalp :: forall c b r r_sub r_sub_rl trash
. Component c b r_sub
=> Row.Union r_sub trash r
=> RL.RowToList r_sub r_sub_rl
=> Keys r_sub_rl
=> c -> Record r -> b
evalp c r = eval c (pick r)
instance evalAdd ::
( Component a Int r_a
, Component b Int r_b
, Row.Union r_a r_b r
, Row.Nub r r_nub
, Row.Union r_a trash_a r_nub
, Row.Union r_b trash_b r_nub
, RL.RowToList r_a r_a_rl
, RL.RowToList r_b r_b_rl
, Keys r_a_rl
, Keys r_b_rl
) => Component (Add a b) Int r_nub where
eval (Add a b) r = (evalp a r) + (evalp b r)
eval (Add (Var :: Var "a" Int) (Var :: Var "b" Int) ) :: { a :: Int , b :: Int } -> Int
eval (Add (Var :: Var "a" Int) (Var :: Var "a" Int) ) :: { a :: Int } -> Int

Related

Why is defining an instance of Choice failing with unknown value?

UPDATE: I'm inlining the code here instead.
I'm trying to define an instance of Data.Profunctor.Choice where right is defined by calling left, but for some reason the compiler complains that left is unknown.
newtype StateTrans s i o = ST (Tuple s i → Tuple s o)
instance stFunctor ∷ Functor (StateTrans s a) where
map f (ST st) = ST $ second f <<< st
instance stProfunctor ∷ Profunctor (StateTrans s) where
dimap f g (ST st) = ST $ second g <<< st <<< second f
instance stChoice ∷ Choice (StateTrans s) where
left (ST f) = ST lf
where
lf (Tuple s (Left a)) = let (Tuple s' b) = f (Tuple s a)
in Tuple s' (Left b)
lf (Tuple s (Right c)) = Tuple s (Right c)
-- Fails to compile with: Unknown value left
right f = arr mirror <<< left f <<< arr mirror
where
mirror Left x = Right x
mirror Right x = Left x
Probably a silly mistake but I've been looking at my code for so long, I can't figure out what's wrong.
(Of minor importance and unrelated: in the Right case for left, I have to unwrap and repackage the value so that it type-aligns. Adding a type ascription fails to compile too.)
Strangely enough, I have no problem doing the same for Strong, see:
instance stStrong ∷ Strong (StateTrans s) where
first (ST f) = ST ff
where
ff (Tuple s (Tuple a c)) = let (Tuple s' b) = f $ Tuple s a
in Tuple s' (Tuple b c)
second f = arr swap <<< first f <<< arr swap
I'm not 100% sure as the pasted snippet doesn't include imports, but I suspect you have an import for Data.Profunctor.Choice (class Choice) rather than Data.Profunctor.Choice (class Choice, left, right).
Importing a class does not import its members implicitly, even though it is possible to define them in an instance without doing so.
First, to use arr you need to declare the Category instance for StateTrans s:
instance stSemigroupoid :: Semigroupoid (StateTrans s) where
compose (ST f1) (ST f2) = ST $ f1 <<< f2
instance stCategory :: Category (StateTrans s) where
id = ST $ \x -> x
For the second step, I needed to add more type annotations (not sure why they're necessary, but this way the build succeeded):
choiceLeft :: forall input output a s. (StateTrans s) input output -> (StateTrans s) (Either input a) (Either output a)
choiceLeft (ST f) = ST lf
where
lf (Tuple s (Left a)) = let (Tuple s' b) = f (Tuple s a)
in Tuple s' (Left b)
lf (Tuple s (Right c)) = Tuple s (Right c)
choiceRight :: forall input output t s. (StateTrans s) input output -> (StateTrans s) (Either t input) (Either t output)
choiceRight f = amirror <<< choiceLeft f <<< amirror
where
mirror :: forall a b. Either a b -> Either b a
mirror (Left x) = Right x
mirror (Right x) = Left x
amirror :: forall a b. StateTrans s (Either b a) (Either a b)
amirror = arr mirror
instance stChoice ∷ Choice (StateTrans s) where
left = choiceLeft
right = choiceRight
Note: used PureScript version 0.11.7 and purescript-profunctor version 3.2.0.

How do I prove a "seemingly obvious" fact when relevant types are abstracted by a lambda in Idris?

I am writing a basic monadic parser in Idris, to get used to the syntax and differences from Haskell. I have the basics of that working just fine, but I am stuck on trying to create VerifiedSemigroup and VerifiedMonoid instances for the parser.
Without further ado, here's the parser type, Semigroup, and Monoid instances, and the start of a VerifiedSemigroup instance.
data ParserM a = Parser (String -> List (a, String))
parse : ParserM a -> String -> List (a, String)
parse (Parser p) = p
instance Semigroup (ParserM a) where
p <+> q = Parser (\s => parse p s ++ parse q s)
instance Monoid (ParserM a) where
neutral = Parser (const [])
instance VerifiedSemigroup (ParserM a) where
semigroupOpIsAssociative (Parser p) (Parser q) (Parser r) = ?whatGoesHere
I'm basically stuck after intros, with the following prover state:
-Parser.whatGoesHere> intros
---------- Other goals: ----------
{hole3},{hole2},{hole1},{hole0}
---------- Assumptions: ----------
a : Type
p : String -> List (a, String)
q : String -> List (a, String)
r : String -> List (a, String)
---------- Goal: ----------
{hole4} : Parser (\s => p s ++ q s ++ r s) =
Parser (\s => (p s ++ q s) ++ r s)
-Parser.whatGoesHere>
It looks like I should be able to use rewrite together with appendAssociative somehow,
but I don't know how to "get inside" the lambda \s.
Anyway, I'm stuck on the theorem-proving part of the exercise - and I can't seem to find much Idris-centric theorem proving documentation. I guess maybe I need to start looking at Agda tutorials (though Idris is the dependently-typed language I'm convinced I want to learn!).
The simple answer is that you can't. Reasoning about functions is fairly awkward in intensional type theories. For example, Martin-Löf's type theory is unable to prove:
S x + y = S (x + y)
0 + y = y
x +′ S y = S (x + y)
x +′ 0 = x
_+_ ≡ _+′_ -- ???
(as far as I know, this is an actual theorem and not just "proof by lack of imagination"; however, I couldn't find the source where I read it). This also means that there is no proof for the more general:
ext : ∀ {A : Set} {B : A → Set}
{f g : (x : A) → B x} →
(∀ x → f x ≡ g x) → f ≡ g
This is called function extensionality: if you can prove that the results are equal for all arguments (that is, the functions are equal extensionally), then the functions are equal as well.
This would work perfectly for the problem you have:
<+>-assoc : {A : Set} (p q r : ParserM A) →
(p <+> q) <+> r ≡ p <+> (q <+> r)
<+>-assoc (Parser p) (Parser q) (Parser r) =
cong Parser (ext λ s → ++-assoc (p s) (q s) (r s))
where ++-assoc is your proof of associative property of _++_. I'm not sure how would it look in tactics, but it's going to be fairly similar: apply congruence for Parser and the goal should be:
(\s => p s ++ q s ++ r s) = (\s => (p s ++ q s) ++ r s)
You can then apply extensionality to get assumption s : String and a goal:
p s ++ q s ++ r s = (p s ++ q s) ++ r s
However, as I said before, we don't have function extensionality (note that this is not true for type theories in general: extensional type theories, homotopy type theory and others are able to prove this statement). The easy option is to assume it as an axiom. As with any other axiom, you risk:
Losing consistency (i.e. being able to prove falsehood; though I think function extensionality is OK)
Breaking reduction (what does a function that does case analysis only for refl do when given this axiom?)
I'm not sure how Idris handles axioms, so I won't go into details. Just beware that axioms can mess up some stuff if you are not careful.
The hard option is to work with setoids. A setoid is basically a type equipped with custom equality. The idea is that instead of having a Monoid (or VerifiedSemigroup in your case) that works on the built-in equality (= in Idris, ≡ in Agda), you have a special monoid (or semigroup) with different underlying equality. This is usually done by packing the monoid (semigroup) operations together with the equality and bunch of proofs, namely (in pseudocode):
= : A → A → Set -- equality
_*_ : A → A → A -- associative binary operation
1 : A -- neutral element
=-refl : x = x
=-trans : x = y → y = z → x = z
=-sym : x = y → y = x
*-cong : x = y → u = v → x * u = y * v -- the operation respects
-- our equality
*-assoc : x * (y * z) = (x * y) * z
1-left : 1 * x = x
1-right : x * 1 = x
The choice of equality for parsers is clear: two parsers are equal if their outputs agree for all possible inputs.
-- Parser equality
_≡p_ : {A : Set} (p q : ParserM A) → Set
Parser p ≡p Parser q = ∀ x → p x ≡ q x
This solution comes with different tradeoffs, namely that the new equality cannot fully substitute the built-in one (this tends to show up when you need to rewrite some terms). But it's great if you just want to show that your code does what it's supposed to do (up to some custom equality).

Is this incremental parser a functor, if so how would `fmap` be implemented?

I really hate asking this kind of question but I'm at the end of my wits here. I am writing an incremental parser but for some reason, just cannot figure out how to implement functor instance for it. Here's the code dump:
Input Data Type
Input is data type yielded by parser to the coroutine. It contains the current list of input chars being operated on by coroutine and end of line condition
data Input a = S [a] Bool deriving (Show)
instance Functor Input where
fmap g (S as x) = S (g <$> as) x
Output Data Type
Output is data type yielded by coroutine to Parser. It is either a Failed message, Done [b], or Partial ([a] -> Output a b), where [a] is the current buffer passed back to the parser
data Output a b = Fail String | Done [b] | Partial ([a] -> Output a b)
instance Functor (Output a) where
fmap _ (Fail s) = Fail s
fmap g (Done bs) = Done $ g <$> bs
fmap g (Partial f) = Partial $ \as -> g <$> f as
The Parser
The parser takes [a] and yields a buffer [a] to coroutine, which yields back Output a b
data ParserI a b = PP { runPi :: [a] -> (Input a -> Output a b) -> Output a b }
Functor Implementation
It seems like all I have to do is fmap the function g onto the coroutine, like follows:
instance Functor (ParserI a) where
fmap g p = PP $ \as k -> runPi p as (\xs -> fmap g $ k xs)
But it does not type check:
Couldn't match type `a1' with `b'
`a1' is a rigid type variable bound by
the type signature for
fmap :: (a1 -> b) -> ParserI a a1 -> ParserI a b
at Tests.hs:723:9
`b' is a rigid type variable bound by
the type signature for
fmap :: (a1 -> b) -> ParserI a a1 -> ParserI a b
at Tests.hs:723:9
Expected type: ParserI a b
Actual type: ParserI a a1
As Philip JF declared, it's not possible to have an instance Functor (ParserI a). The proof goes by variance of functors—any (mathematical) functor must, for each of its arguments, be either covariant or contravariant. Normal Haskell Functors are always covariant which is why
fmap :: (a -> b) -> (f a -> f b)`
Haskell Contravariant functors have the similar
contramap :: (b -> a) -> (f a -> f b)`
In your case, the b index in ParserI a b would have to be both covariant and contravariant. The quick way of figuring this out is to relate covariant positions to + and contravariant to - and build from some basic rules.
Covariant positions are function results, contravariant are function inputs. So a type mapping like type Func1 a b c = (a, b) -> c has a ~ -, b ~ -, and c ~ +. If you have functions in output positions, you multiply all of the argument variances by +1. If you have functions in input positions you multiply all the variances by -1. Thus
type Func2 a b c = a -> (b -> c)
has the same variances as Func1 but
type Func3 a b c = (a -> b) -> c
has a ~ 1, b ~ -1, and c ~ 1. Using these rules you can pretty quickly see that Output has variances like Output - + and then ParserI uses Output in both negative and positive positions, thus it can't be a straight up Functor.
But there are generalizations like Contravariant. The particular generalization of interest is Profunctor (or Difunctors which you see sometimes) which goes like so
class Profunctor f where
promap :: (a' -> a) -> (b -> b') -> (f a b -> f a' b')
the quintessential example of which being (->)
instance Profunctor (->) where
promap f g orig = g . orig . f
i.e. it "extends" the function both after (like a usual Functor) and before. Profunctors f are thus always mathematical functors of arity 2 with variance signature f - +.
So, by generalizing your ParserI slightly, letting there be an extra parameter to split the ouput types in half, we can make it a Profunctor.
data ParserIC a b b' = PP { runPi :: [a] -> (Input a -> Output a b) -> Output a b' }
instance Profunctor (ParserIC a) where
promap before after (PP pi) =
PP $ \as k -> fmap after $ pi as (fmap before . k)
and then you can wrap it up
type ParserI a b = ParserIC a b b
and provide a slightly less convenient mapping function over b
mapPi :: (c -> b) -> (b -> c) -> ParserI a b -> ParserI a c
mapPi = promap
which really drives home the burden of having the variances go both ways---you need to have bidirectional maps!

How to restrict backtracking in a monad transformer parser combinator

tl;dr, How do I implement parsers whose backtracking can be restricted, where the parsers are monad transformer stacks?
I haven't found any papers, blogs, or example implementations of this approach; it seems the typical approach to restricting backtracking is a datatype with additional constructors, or the Parsec approach where backtracking is off by default.
My current implementation -- using a commit combinator, see below -- is wrong; I'm not sure about the types, whether it belongs in a type class, and my instances are less generic than it feels like they should be.
Can anyone describe how to do this cleanly, or point me to resources?
I've added my current code below; sorry for the post being so long!
The stack:
StateT
MaybeT/ListT
Either e
The intent is that backtracking operates in the middle layer -- a Nothing or an empty list wouldn't necessarily yield an error, it'd just mean that a different branch should be tried -- whereas the bottom layer is for errors (with some contextual information) that immediately abort the parsing.
{-# LANGUAGE NoMonomorphismRestriction, FunctionalDependencies,
FlexibleInstances, UndecidableInstances #-}
import Control.Monad.Trans.State (StateT(..))
import Control.Monad.State.Class (MonadState(..))
import Control.Monad.Trans.Maybe (MaybeT(..))
import Control.Monad.Trans.List (ListT(..))
import Control.Monad (MonadPlus(..), guard)
type Parser e t mm a = StateT [t] (mm (Either e)) a
newtype DParser e t a =
DParser {getDParser :: Parser e t MaybeT a}
instance Monad (DParser e t) where
return = DParser . return
(DParser d) >>= f = DParser (d >>= (getDParser . f))
instance MonadPlus (DParser e t) where
mzero = DParser (StateT (const (MaybeT (Right Nothing))))
mplus = undefined -- will worry about later
instance MonadState [t] (DParser e t) where
get = DParser get
put = DParser . put
A couple of parsing classes:
class (Monad m) => MonadParser t m n | m -> t, m -> n where
item :: m t
parse :: m a -> [t] -> n (a, [t])
class (Monad m, MonadParser t m n) => CommitParser t m n where
commit :: m a -> m a
Their instances:
instance MonadParser t (DParser e t) (MaybeT (Either e)) where
item =
get >>= \xs -> case xs of
(y:ys) -> put ys >> return y;
[] -> mzero;
parse = runStateT . getDParser
instance CommitParser t (DParser [t] t) (MaybeT (Either [t])) where
commit p =
DParser (
StateT (\ts -> MaybeT $ case runMaybeT (parse p ts) of
Left e -> Left e;
Right Nothing -> Left ts;
Right (Just x) -> Right (Just x);))
And a couple more combinators:
satisfy f =
item >>= \x ->
guard (f x) >>
return x
literal x = satisfy (== x)
Then these parsers:
ab = literal 'a' >> literal 'b'
ab' = literal 'a' >> commit (literal 'b')
give these results:
> myParse ab "abcd"
Right (Just ('b',"cd")) -- succeeds
> myParse ab' "abcd"
Right (Just ('b',"cd")) -- 'commit' doesn't affect success
> myParse ab "acd"
Right Nothing -- <== failure but not an error
> myParse ab' "acd"
Left "cd" -- <== error b/c of 'commit'
The answer appears to be in the MonadOr type class (which unfortunately for me is not part of the standard libraries):
class MonadZero m => MonadOr m where
morelse :: m a -> m a -> m a
satisfying Monoid and Left Catch:
morelse mzero b = b
morelse a mzero = a
morelse (morelse a b) c = morelse a (morelse b c)
morelse (return a) b = return a

How can I make a Maybe-Transformer MaybeT into an instance of MonadWriter?

I am trying to build a MaybeT-Transformer Monad, based on the example in the Real World Haskell, Chapter Monad Transformers:
data MaybeT m a = MaybeT { runMT :: m (Maybe a) }
instance (Monad m) => Monad (MaybeT m) where
m >>= f = MaybeT $ do a <- runMT m
case a of
Just x -> runMT (f x)
Nothing -> return Nothing
return a = MaybeT $ return (Just a)
instance MonadTrans MaybeT where
lift m = MaybeT $ do
a <- m
return (Just a)
This works fine, but now I want to make MaybeT an instance of MonadWriter:
instance (MonadWriter w m) => MonadWriter w (MaybeT m) where
tell = lift . tell
listen m = MaybeT $ do unwrapped <- listen (runMT m)
return (Just unwrapped)
The tell is ok, but I can't get the listen function right. The best I could come up with after 1 1/2 days of constructor origami is the one you see above: unwrapped is supposed to be a tuple of (Maybe a, w), and that I want to wrap up in a Maybe-Type and put the whole thing in an empty MonadWriter.
But the compiler complains with:
Occurs check: cannot construct the infinite type: a = Maybe a
When generalising the type(s) for `listen'
In the instance declaration for `MonadWriter w (MaybeT m)'
What am I missing?
listen has type signature
m a -> m (a, w)
i.e.
MaybeT m a -> MaybeT m (a, w)
But MaybeT $ listen (runMT m) >>= return . Just has type signature
MaybeT m a -> MaybeT m (Maybe a, w)
so the infinite type error is raised. You need to convert that unwrapped :: (Maybe a, w) into a Maybe (a, w) to proceed:
listen m = MaybeT $ do (val, wr) <- listen (runMT m)
case val of
Nothing -> return Nothing
Just x -> return (Just (x, wr))
(BTW, there is an implementation of MaybeT in http://www.haskell.org/haskellwiki/New_monads/MaybeT.)

Resources