Using interfaces to define partial functions on Type - typeclass

I'm trying to define something in Idris which would provide a way to represent types typographically. Think about Show, but instead of Showing elemenents of a type, I want to show the type itself. That would have the same practical effect of having defined a partial function on Type (that gives a type's representation) that a user could extend for their types as well.
My first idea, given the “user can extend functionality” requirement, was to use interfaces. So that would look something like this:
interface Representable a where
representation : String
Some possible implementation would be
Representable Nat where
representation = "Nat"
However, I come to a problem. Let's say I want to define a representation of the function type. That would be the representation of its domain, an arrow, and a representation of its range. So something like
(Representable a, Representable b) => Representable (a -> b) where
representation = representation ++ " -> " ++ representation
The problem is now obvious. The compiler can't infer the representation's types on the right-hand side.
One alternative I came up with would be to create a Representation type that would carry an “artificial” argument:
data Representation : Type -> Type where
Repr : (a : Type) -> String -> Representation a
Which would lead to
interface Representable a where
representation : Representation a
And then
Representable Nat where
representation = Repr Nat "Nat"
(Representable d, Representable r) => Representable (d -> r) where
representation = Repr (d -> r) $
(the (Representation d) representation)
++ " -> "
++ (the (Representation r) representation)
But then, off course, I get the error
Representations.idr:13:20-127:
|
13 | representation = Repr (d -> r) $ (the (Representation d) representation) ++ " -> " ++ (the (Representation r) representation)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When checking right hand side of Representations.Representations.d -> r implementation of Representations.Representable, method representation with expected type
Representation (d -> r)
When checking argument a to constructor Representations.Repr:
No such variable d
However, I want representation to be argumentless – obviously, as it is a representation of the type, not its elements.
Does anyone have any sugestion on how to fix this particular error, or better yet, how to implement my idea in some not-so-horrifying-way?

You can take an idea from Haskell and use a proxy to pass a token to representation with no term-level content:
data Proxy a = MkProxy
interface Representable a where
representation : Proxy a -> String
Representable Nat where
representation _ = "Nat"
(Representable a, Representable b) => Representable (a -> b) where
representation {a = a} {b = b} _ = representation (MkProxy {a = a}) ++ " -> " ++ representation (MkProxy {a = b})

Related

Parser with multiple return types

I have problem with parsers that can manage multiple types, e.g., the parser for arithmetic expressions. At the moment my parser takes in input only integers:
aexpr :: Parser Int
aexpr = aterm `chainl` addOp
aterm :: Parser Int
aterm = afactor `chainl` mulOp
afactor :: Parser Int
afactor = parenP '(' aexpr ')'
<|>
do
s <- sign
a <- aexpr
return (s * a)
<|>
token int_const
This works well for two integers, but I am introducing the float type, so the parser for arithmetic expressions can have in input two Int, two Float or two mixed types of Int and Float. The result type of the parser should be Int or Float based on the inputs (i.e., Int if both inputs are Int, Float otherwise).
My question is: what is the best way to manage this? A simple way is to just manage all the inputs as Float, so integer values are converted into float values. But I don't like this solution: the end result will be always Float.
Should I create two different parsers, i.e., one for Int and one for Float? But the two parsers would be pretty much the same.
There is a better solution?
When designing DSLs, it's very common to define a new data type representing all the different shapes values can have:
data Value
= I Int
| D Double
deriving (Eq, Ord, Read, Show)
You may want to implement some helper functions, like:
binOp :: (forall a. Num a => a -> a -> a) -> Value -> Value -> Parser Value
binOp f (I a) (I b) = pure (I (f a b))
binOp f (D a) (D b) = pure (D (f a b))
binOp _ _ _ = fail "oof, tried to mix Ints and Doubles"
Then your mulOp and addOp implementations could call binOp (*) and binOp (+) somewhere in their implementation, for example.
But I would consider another approach than using such helpers directly. I would propose introducing an intermediate representation for which parsing "always succeeds", then add a separate type-checking phase where you can throw errors about mixing ints and doubles... or do appropriate casts, or whatever your DSL wants to happen there. So:
data BinOp = Plus | Times deriving (Bounded, Enum, Eq, Ord, Read, Show)
data Type = Int | Double deriving (Bounded, Enum, Eq, Ord, Read, Show)
data DSL
= ILit Int
| DLit Double
| BinOp BinOp DSL DSL
deriving (Eq, Ord, Read, Show)
Then you can write things with types like
typeCheck :: DSL -> These [TypeError] Type -- check for mixing
unsafeEval :: DSL -> Value -- implementation uses incomplete patterns and assumes no mixing
eval :: DSL -> Either [TypeError] Value
eval t = case typeCheck t of
That _ -> Right (unsafeEval t)
These [] _ -> Right (unsafeEval t)
These es _ -> Left es
This es -> Left es
or whatever.

Backtracking Recursive Descent Parser for the following grammar

I am trying to figure out some details involving parsing expression grammars, and am stuck on the following question:
For the given grammar:
a = b Z
b = Z Z | Z
(where lower-case letters indicate productions, and uppercase letters indicate terminals).
Is the production "a" supposed to match against the string "Z Z"?
Here is the pseudo-code that I've seen the above grammar get translated to, where each production is mapped to a function that outputs two values. The first indicates whether the parse succeeded. And the second indicates the resulting position in the stream after the parse.
defn parse-a (i:Int) -> [True|False, Int] :
val [r1, i1] = parse-b(i)
if r1 : eat("Z", i1)
else : [false, i]
defn parse-b1 (i:Int) -> [True|False, Int] :
val [r1, i1] = eat("Z", i)
if r1 : eat("Z", i1)
else : [false, i]
defn parse-b2 (i:Int) -> [True|False, Int] :
eat("Z", i)
defn parse-b (i:Int) -> [True|False, Int] :
val [r1, i1] = parse-b1(i)
if r1 : [r1, i1]
else : parse-b2(i)
The above code will fail when trying to parse the production "a" on the input "Z Z". This is because the parsing function for "b" is incorrect. It will greedily consume both Z's in the input and succeed, and then leave nothing left for a to parse. Is this what a parsing expression grammar is supposed to do? The pseudocode in Ford's thesis seems to indicate this.
Thanks very much.
-Patrick
In PEGs, disjunctions (alternatives) are indeed ordered. In Ford's thesis, the operator is written / and called "ordered choice", which distinguishes it from the | disjunction operator.
That makes PEGs fundamentally different from CFGs. In particular, given PEG rules a -> b Z and b -> Z Z / Z, a will not match Z Z.
Thanks for your reply Rici.
I re-read Ford's thesis much more closely, and it reaffirms what you said. PEGs / operator are both ordered and greedy. So the rule presented above is supposed to fail.
-Patrick

How to reference type class-polymorphic variables in a theorem type?

I have written a Haskell-style Functor type class:
Class Functor (f: Type -> Type) := {
map {a b: Type}: (a -> b) -> (f a -> f b);
map_id: forall (a: Type) (x: f a), map id x = x
}
Where id has the obvious definition.
Now, I've proven instances of Functor for list and the function type. But I want to prove statements about any functor. To start with, I want to prove what's essentially a tautology: a restatement of the map_id for any functor.
Theorem map_id_restatement: forall (F: Type -> Type),
Functor F -> forall T (x: F T), map id x = x.
The idea being to prove this theorem I would simply apply map_id. But I get an error when I try to start proving this:
Toplevel input, characters 88-91:
Error:
Could not find an instance for "Functor F" in environment:
F : Type -> Type
T : Type
x : F T
But the Functor F instance should be already in scope due to the assumption in the type. Why is it not recognized?
Edit:
OK, I figured out I could make it work by quantifying the Functor F:
Theorem map_id_restatement: forall (F: Type -> Type) (finst: Functor F),
forall T (x: F T), map id x = x.
Proof. apply #map_id. Qed.
Why is this necessary? Interestingly, it doesn't work if I don't explicitly give a name to the functor instance (i.e. if I just write (_: Functor F)).
I don't know whether this is a bug or not, but notice that when you write something like Functor F -> SomeType, you are implicitly saying that SomeType does not depend on the Functor instance, which is not true in your case: the full type of your theorem, printing all implicit arguments, would be something like:
Theorem map_id_restatement: forall (F: Type -> Type) (finst: Functor F),
forall T (x: F T), #map F fints T T (#id T) x = x.
If you replace finst by _, you get
Theorem map_id_restatement: forall (F: Type -> Type) (_: Functor F),
forall T (x: F T), #map F _ T T (#id T) x = x.
which can't really be type-checked, since _ is not really a variable name.
Notice that, if you bind Functor F anonymously before the colon, Coq accepts it:
Theorem map_id_restatement (F: Type -> Type) (_ : Functor F) :
forall T (x: F T), map (#id T) x = x.
Proof. apply #map_id. Qed.
Presumably, here Coq is treating the _ in a different way, and replacing it by an automatically generated name, instead of actually leaving it unnamed. You can also use the following form, which works both under the forall or before the colon:
Theorem map_id_restatement (F: Type -> Type) : forall `(Functor F),
forall T (x: F T), map (#id T) x = x.
Proof. apply #map_id. Qed.

In Agda is it possible to define a datatype that has equations?

I want to describe the integers:
data Integer : Set where
Z : Integer
Succ : Integer -> Integer
Pred : Integer -> Integer
?? what else
The above does not define the Integers. We need Succ (Pred x) = x and Pred (Succ x) = x. However,
spReduce : (m : Integer) -> Succ (Pred m) = m
psReduce : (m : Integer) -> Pred (Succ m) = m
Can't be added to the data type. A better definition of the integers is most certainly,
data Integers : Set where
Pos : Nat -> Integers
Neg : Nat -> Integers
But I am curious if there is a way to add equations to a datatype.
I'd go about it by defining a record:
record Integer (A : Set) : Set where
constructor integer
field
z : A
succ : A -> A
pred : A -> A
spInv : (x : A) -> succ (pred x) == x
psInv : (x : A) -> pred (succ x) == x
This record can be used as a proof that a certain type A behaves like an Integer should.
It seems that what you'd like to do is define your Integers type as a quotient type by the equivalence relation that identifies Succ (Pred m) with m, etc. Agda doesn't support that anymore -- there was an experimental library that tried to do that (by forcing all functions over a quotient type to be defined via a helper function that requires proof of representational invariance), but then someone discovered that the implementation wasn't watertight enough and so could lead to inconsistencies (basically by accessing one of its postulates that was supposed to be inaccessible from the outside), for the details you can see this message:
We were not sure if this hack was sound or not. Now, thanks to Dan
Doel, I know that it isn't.
[...]
Given these observations it is easy to prove that the postulate above
is unsound:
I think your best bet at the moment (if you want to/need to stick to a loose representation with an equivalency to tighten it up) is to define a Setoid for your type..

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!

Resources