How to make use of information known about this function type in Coq - variadic-functions

Say I have the following type typ representing bool or nat:
Inductive typ : Type := TB | TN.
I also have a function to extract an actual function type from a list of typs and a result type:
Fixpoint get_types (s: seq typ) (result_type: Type) : Type :=
match s with
| nil => result_type
| x :: xs => match x with
| TN => nat -> get_types xs result_type
| TB => bool -> get_types xs result_type
end
end.
Example get_types_works : get_types (TB :: TN :: nil) nat = bool -> nat -> nat.
Proof. by []. Qed.
Now, I have another function that takes as input a list s of typs and a function of type get_types s:
Fixpoint app (s: seq typ) (constructor: get_types s nat) : nat :=
match s with
| nil => 2 (* Not properly handling empty list case for now *)
| TB :: nil => constructor true
| TN :: nil => constructor 2
| TB :: xs => app xs (constructor true)
| TN :: xs => app xs (constructor 2)
end.
Defining the above function fails at the line | TB :: nil => constructor true with:
Illegal application (Non-functional construction):
The expression "constructor" of type "get_types s nat" cannot be applied to the term
"true" : "bool"
Given we know here that the type of get_types s nat should be bool -> nat, as the value of s is TB :: nil, I'm wondering if there's a way we can make Coq aware of this so that the above function can be defined?
If not, is this a limitation of Coq or would the same apply to other dependently typed languages?
Edit: For context, this is not the original problem I'm trying to solve; it's a condensed version to show the issue I was having with the type system. In the actual version, rather than hard-coding 2 and true, the typ-like datastructure also carries indices of data to parse from a memory slice, and validation functions. The aim for app is a function that takes a list of such typs, a slice, and a constructor for a record containing such types, then constructs an instance of that record from the indices of the types to parse, or returns None if any of the validations fail.

There's nothing wrong with what you want in principle. However, at least in Coq, there are some simple rules for how pattern matching is typechecked so that information about which constructor was used can be used in the type. The surface language (Gallina in this case) hides this simplicity by helping compile (or desugar) pattern matches, so that as a user you can write more complex patterns than the underlying system has to deal with. I'm not as familiar with Idris, but based on how complicated dependent pattern matches can be I suspect you run into similar limitations there, where you have to fit your code into a form the system can type check.
Here, you're running into two limitations of this pattern matching compilation. The first is that the type of constructor is not specialized based on the match on s. This is easily fixed by computing a function from get_types s nat -> nat, which the compiler gets right.
Require Import List.
Import ListNotations.
Inductive typ : Type := TB | TN.
Fixpoint get_types (s: list typ) (result_type: Type) : Type :=
match s with
| nil => result_type
| x :: xs => match x with
| TN => nat -> get_types xs result_type
| TB => bool -> get_types xs result_type
end
end.
Fail Fixpoint app (s: list typ) : get_types s nat -> nat :=
match s with
| nil => fun constructor => 2
| TB :: nil => fun constructor => constructor true
| TN :: nil => fun constructor => constructor 2
| TB :: xs => fun constructor => app xs (constructor true)
| TN :: xs => fun constructor => app xs (constructor 2)
end.
(* fails due to limitation of termination checker with nested matches *)
...but then you run into a second problem with the termination checker. Note that your match is complex: it analyzes the structure of s as well as its head and tail (if it was built with cons). Ultimately all pattern matches are compiled to nested pattern matches on a single inductive type. If you look at this unfolding, you're destructing s into t::xs, and then destructing xs again into t0::xs', before finally recursing on xs. Unfortunately, the Coq termination checker only sees this as t0::xs' and doesn't recognize it as a subterm of s (it really wants xs).
I had a hard time manually writing your function in a way that type checks, but here's a version written using tactics that is functionally correct. Note that the definition it produces is quite a bit more complicated than any ordinary pattern match, because it has to maintain a proof produced by destruct_with_eqn. However, that proof is crucial to simultaneously using xs to make the termination checker happy and revealing t0::xs' for type checking the application of the constructor. It may be complicated but you can still run it just fine, as the last line illustrates.
Fixpoint app (s: list typ) (constructor: get_types s nat) {struct s} : nat.
destruct s as [|t xs]; simpl in *.
exact 2.
destruct_with_eqn xs; simpl in *.
destruct t; [ exact (constructor true) | exact (constructor 2) ].
destruct t; simpl in *.
- apply (app xs).
subst.
exact (constructor true).
- apply (app xs).
subst.
exact (constructor 2).
Defined.
Eval compute in app [TB; TN] (fun x y => if x then y+2 else y).
(* = 4
: nat
*)

Because you tagged this with Idris, here is how it works there:
data Typ = TB | TN
get_types : (args : List Typ) -> (res : Type) -> Type
get_types [] res = res
get_types (TB :: xs) res = Bool -> get_types xs res
get_types (TN :: xs) res = Nat -> get_types xs res
app : (args : List Typ) -> (con : get_types args Nat) -> Nat
app [] con = 2
app (TB :: []) con = con True
app (TN :: []) con = con 2
app (TB :: xs) con = app xs (con True)
app (TN :: xs) con = app xs (con 2)
Basically, you don't have the problem, because with matching on args, the compiler also infers the type for con. For example, if you replace the last case with
app (TN :: xs) con = ?hole
and investigate the hole, you see that the compiler has new information about con:
xs : List Typ
con : Nat -> get_types xs Nat
--------------------------------------
hole : Nat

Yet two other ways of defining app.
The first one uses tactics, and relies on induction instead of Fixpoint.
Definition app (s: seq typ) (constructor: get_types s nat) : nat.
Proof.
induction s as [|t xs].
- exact 2.
- destruct xs.
+ destruct t.
* exact (constructor true).
* exact (constructor 2).
+ destruct t.
* exact (IHxs (constructor true)).
* exact (IHxs (constructor 2)).
Defined.
The second one uses Gallina and complexed pattern-matchings.
Fixpoint app (s: seq typ) : get_types s nat -> nat :=
match s return get_types s nat -> nat with
| nil => fun _ => 2
| x :: xs =>
match xs as xs0 return xs = xs0 -> get_types (x::xs0) nat -> nat with
| nil => fun _ => match x return get_types (x::nil) nat -> nat with
| TB => fun c => c true
| TN => fun c => c 2
end
| _ => fun e => match e in _ = xs1 return get_types (x::xs1) nat -> nat with
| eq_refl =>
match x return get_types (x::xs) nat -> nat with
| TB => fun c => app xs (c true)
| TN => fun c => app xs (c 2)
end
end
end eq_refl
end.
When destructing xs, we remember an equality between the original xs and what it is destructed in. We do not need this equality in the nil branch and discards it with fun _. In the other branch, we pattern-match on the proof of equality (match e), which corresponds to a rewriting using this equality. Inside the eq_refl branch, we can use the original xs and thus make recursive calls allowed by the termination checker. Outside the pattern-match, we return the right type expected by the pattern-matching on xs. The last thing to do is to provide a proof of the equality of xs and xs0, but it is trivially eq_refl.

Well, I am not sure what you are really trying to do, but the first step to submit your code into the "convoy" pattern is indeed to add a bit more structure to you type interpretation. If you separate the interpretation of types from the one for list of types you can easily get a skeleton working:
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Inductive Typ := TB | TN.
(* Interpretation for types *)
Definition iT w : Type :=
match w with | TB => bool | TN => nat end.
(* Default witness *)
Definition dw w : iT w :=
match w with | TB => true | TN => 2 end.
Definition get_types (res : Type) := fix gt (args : list Typ) :=
match args with
| [::] => res
| [:: w & xs] => iT w -> gt xs
end.
Variable (dt : Typ).
Fixpoint app (args : list Typ) : get_types (iT dt) args -> iT dt :=
match args with
| [::] => fun gt => dw dt
| [:: tw & xs] => fun gt => app (gt (dw tw))
end.
Note that I've generalized the return type too as there was no good reason to hardcode the definition to nat. A fun exercise is to modify the above app function and prove it equivalent to the tactic-based version of Tej.

Related

Propositional logic in haskell

I have the following data types
data Prop =
Var Name
| Neg Prop
| Conj Prop Prop
| Disy Prop Prop
| Impl Prop Prop
| Syss Prop Prop deriving Show -- if and only if
-- And the following
type Name = String
type State = (Name, Bool) -- The state of a proposition, Example ("P", True), ("Q", True)
type States = [State] -- A list of states, [("P", True), ("Q", False), ...]
type Row = (States, Bool) -- A row of the table. ([("P", True), ("Q", False), ...], True)
type Table = [Row]
The case is that I want to generate all the possible states of a proposition
P, Q, R
1 1 1
1 1 0
1 0 1
...
To do this, I create auxiliary functions to gradually build the states
-- Get all the atoms of a proposition
varList :: Prop -> [Name]
varList (Var p) = [p]
varList (Neg p) = varList p
varList (Conj p q) = varList p ++ varList q
varList (Disy p q) = varList p ++ varList q
varList (Impl p q) = varList p ++ varList q
varList (Syss p q) = varList p ++ varList q
--Power set to get all values
conjPoten :: Eq a => [a] -> [[a]]
conjPoten [] = [[]]
conjPoten (x:xs) = map (x: ) pt `union` pt
where
pt = conjPoten xs
-- Give value to a proposition, "P" -> True, "" -> False
giveValue:: Name -> Bool
giveValue p = p /= []
-- Generate a State, "P" -> ("P",True), "" -> ("",False)
generateState :: Name -> State
generateState p = (p , daValor p)
-- The function that I want
generateStates:: [Name] -> States
generateStates p = [(a,True) | a <-p]
This, of course, is a test to verify that "it works", because if
generateStates ["P","Q", "R"] = [("P",True),("Q",True),("R",True)]
I did this thinking that in the power set we are going to have cases like ["P","Q","R"] and ["P","Q"], that is, there is not going to be "R". So the intention is that
["P","Q","R"] gives us [("Q",True),("P",True),("R",True)] and
["P","Q"] gives us [("Q",True),("P",True),("R",False)]
But from here I have two questions
The first is, that I have to modify the second element of the tuple, so what I came up with was
generateStates :: [Name] -> States
generateStates p = [ (a, b) | a<- p, a<- giveValue p]
The main error that the prelude marks me is:
Couldn't match type ‘[Char]’ with ‘Char’
Which I understand, because p is a list and giveValue works with a Name, not with a list of Names
So my question is: How do I get that p out of a Name? and that it does not stay as a list of Name
I tried to do it like
generateStates :: [Name] -> States
generateStates [p] = [ (p, b) | a<- giveValue p]
But that tells me:
Couldn't match expected type ‘[Bool]’ with actual type ‘Bool’
Which, now I don't understand, plus it tells me there aren't enough patterns
Why does this happen?
The other question is that, having
generateStates :: [Name] -> States
generateStates p = [ (a, True) | a<-p]
and try it with
generateStates ["P","Q"] would only give me [("Q",True),("P",True)]
But we have P, Q and R, so I'm missing the ("R", False)
But since it is in the arguments that we pass, it cannot add it to the list
Where do I get that R? those missing variables?
Thanks!
To change the tuple, you really create a new one, as they are not mutable. You could create a function using pattern matching. The below function works on pairs (tuples with two elements).
modTuple (firstValue, secondValue) updatedValue = (firstValue, updatedValue)
Alternatively you could access the members of the tuple with the built-in fst and snd to access the first and second elements, and create a new tuple.
You can use pattern matching to access individual elements of a list, and build up States recursively. I.e.
generateStates [] = []
generateStates (p:ps) = (p, giveValue p):(generateStates ps)

Concatenating strings together into a list

What I'm trying to do is that I want to take a list of strings as input and do some operations then return back a list of strings. The problem is, I am looking for specific yet generic patterns of the string for each case:
func :: [String] -> [String]
func [] = []
func [x] = [x]
func (["Not","(","Not"]:es:[")"]) = es --HERE
func ("Not":"(":pred:"And":rest:")") = ("Not":pred:"Or":(pushNotInwards rest))
func ("Not":"(":pred:"Or":rest:")") = ("Not":pred:"And":(pushNotInwards rest))
func ("Not":"(":"ForAll":x:scope:")") = ("Exists":"Not":"("scope:")")
func ("Not":"(":"Exists":x:scope:")") = ("ForAll":"Not":"(":scope:")")
For the third case for instance, I want to take a list of strings in the form of:
["Not","(","Not",some_strings,")"]
I tried using ++ on the left hand side as:
func (["Not"]++["("]++["Not"])++es++[")"]) = es
I also tried concat and : but they didn't work either. Any suggestions?
You seem to have some confusion about the different string operators.
A String is just a synonym for a list of chars i.e. [Char]. The colon : operator (aka cons) adds one element to the beginning of a list. Here's its type:
*Main> :t (:)
(:) :: a -> [a] -> [a]
For example:
*Main> 1:[2,3]
[1,2,3]
*Main> 'a':"bc"
"abc"
The ++ operator concatenates two lists. Here's its type:
*Main> :t (++)
(++) :: [a] -> [a] -> [a]
Pattern matching can only be done using a data constructor. The : operator is a data constructor, but the ++ operator is not. So you cannot define a function using pattern matching over the ++ operator.
To define a function using pattern matching, I'd suggest defining a new data type for the different functions and qualifier rather than using strings:
-- Logic Operation
data LogicOp =
Not LogicOp | And [LogicOp] | Or [LogicOp] |
Forall String LogicOp | Exists String LogicOp | T | F
deriving (Eq, Show)
func :: LogicOp -> LogicOp
func (Not (Not x)) = x
func (Not (And (pred:rest))) = Or (Not pred:[func (Not (And rest))])
func (Not (Or (pred:rest))) = And (Not pred:[func (Not (Or rest))])
func (Not (Forall x scope)) = Exists x (Not scope)
func (Not (Exists x scope)) = Forall x (Not scope)
func x = x
Here are some examples:
*Main> func (Not (Not T))
T
*Main> func (Not (And [T, F, T]))
Or [Not T,Or [Not F,Or [Not T,Not (And [])]]]
*Main> func (Not (Or [T, F, T]))
And [Not T,And [Not F,And [Not T,Not (Or [])]]]
*Main> func (Not (Forall "x" (And T F))
*Main> func (Not (Forall "x" (And [T, F])))
Exists "x" (Not (And [T,F]))
*Main> func (Not (Exists "x" (And [T, F])))
Forall "x" (Not (And [T,F]))
You should probably not use strings for that. Create a new type:
data SomeExpr = Not SomeExpr
| And SomeExpr SomeExpr
| Or SomeExpr SomeExpr
deriving (Show)
Then you could match on that expression:
func :: SomeExpr -> SomeExpr
func (Not (Not x)) = func x
func (Not (And x y)) = Or (Not $ func x) (Not $ func y)
func (Not (Or x y)) = And (Not $ func x) (Not $ func y)
...
func x = x
You can't pattern match a list in the middle, e.g You want to match [1,2,3,4,5] with (1:middle:5:[]), but this is invalid.
Yes, using an own type has it's own problems, you have to parse it etc, but it is much more easier and safer than with strings (which could have arbitrary content).

Type error in explicitly typed binding in Haskell

I'm a having a type error on my Haskell Code. termEnVoc is expected to return True if the Term given is part of the Vocabulario (vocabulary), I'm not completely sure if it works but anyway I can't understand why do I get a type error.
Here it's the code:
type Cte = Simbolo
type Funcion = (Simbolo,Aridad)
type Predicado = (Simbolo, Aridad)
type Vocabulario = ([Cte], [Funcion], [Predicado])
data Term = C Simbolo | L Var | F Simbolo [Term]
deriving (Show, Eq)
termEnVoc :: Term -> Vocabulario -> Bool --This is line 38, the one with the error
termEnVoc = \t -> \(cs,fs,ps)-> (or(map (\x ->(x==t))cs) || or(map (\x ->(x==t))f) || or(map (\x ->(x==t))p));
And here the error:
ERROR file:.\tarea3.hs:38 - Type error in explicitly typed binding
*** Term : termEnVoc
*** Type : [Char] -> ([[Char]],[([Char],Int)],[([Char],Int)]) -> Bool
*** Does not match : Term -> Vocabulario -> Bool
As chi suggests, the main problem appears to be that you are trying to compare Terms with values of other types. It's hard to see just what you're trying to do (specifically, what different types are supposed to represent), but here's the general way you probably want to structure the function definition:
termEnVoc (C simbolo) (cs, fs, ps) = cte `elem` cs
termEnVoc (F simbolo termList) (cs, fs, ps) = head $ filter ((== f) . fst) fs
termEnVoc (L var) (cs, fs, ps) = head $ filter ((== var) . fst) ps
As I indicated, some (or even most) of the details may be wrong, but this should give you a sense of how to structure the definition. The code above makes use of the following:
(== x) = (\y -> y == x)
You can actually do this with operators in general:
(/ 3) = (\x -> x/3)
and
(3 /) = (\x -> 3/x)
The only one that's wonky is subtraction, and I always have to look up the rules for that.
elem a as = or $ map (== a) as
a `elem` b = elem a b
filter p [] = []
filter p (x:xs)
| p x = x : filter p xs
| otherwise = filter p xs
Note that the real definitions of the above are likely different, for efficiency reasons.
I finally decided that the problem was as dfeuer said that I was comparing terms with values of other types.
I end up with this method:
esTerm :: Vocabulario -> Term -> Bool
esTerm = \(c,f,p)-> \t -> case t of {
C x -> elem x c;
L x -> True;
F n ts -> case (lookup n f) of {
Nothing -> False;
Just x -> x==(length ts)&& and(map (esTerm (c,f,p)) ts);
}
}
Thanks for the help, it was really useful for fixing other mistakes I was making on my project.

Haskell beginner: Data decl. errors

Hello I am trying to write a very simple function in Haskell. However I can't get "ghci" to accept my code.
data Field = A1 Int deriving (Show)
data FieldList = FL [Field] | Name String deriving (Show)
t :: Field
t = A1 1
u :: Int -> FieldList
u 0 = FL []
u n = FL [t]:(u (n-1))
And the error I get is this:
test.hs:9:7:
Couldn't match expected type `FieldList' with actual type `[a0]'
In the expression: (FL [t]) : (u (n - 1))
In an equation for `u': u n = (FL [t]) : (u (n - 1))
Can someone point me in the right direction?
Thanks!
Looking at the last line:
u n = FL [t]:(u (n-1))
u has the type Int -> FieldList. n is an Int, so (n - 1) is also an Int. u (n-1) would therefor be a FieldList.
Function application has a higher precedence than operators, so the above line is equivalent to:
u n = (FL [t]) : (u (n - 1) )
FL [t] is a FieldList.
However, (:) has the type a -> [a] -> [a]. You can see the types don't match, so that is what is causing the problem.
What you probably want to do is build up the list of Fields (having type [Field]), and then turning that into a FieldList. Here is some stub code:
u :: Int -> FieldList
u n = FL (uHelper n)
uHelper :: Int -> [Field]
uHelper = ... -- write this function
The error says (FL [t]) : (u (n - 1)) which says that you are trying the List cons function on
FL [t] which is not a list hence you cannot cons with it.
I am not sure why you have created a FieldList as a new data type which allows a FieldList to be either a List of Field OR a string (which is created using Name constructor) which sort of doesn't make logical sense.
What you can do is make FieldList as:
type FieldList = [Field]
And then your function would become:
u :: Int -> FieldList
u 0 = []
u n = t : (u (n-1))
There are two problems with your code:
The first argument of list cons (:) is an element, not a list, thus: t : ... not [t] : ...
You must unwrap the FieldList first to get [Field]. Then you can prepend t to it.
You want your last line to be
u n = case u (n-1) of FL xx -> FL (t:xx)
That would of course fail to pattern match if the field list is a Name so I would agree with Ankur that there might be a problem with the design...

Haskell: Recursion with a polymorphic equality function

Ok so we have not learned polymorphic functions yet, but we still have to write this code.
Given:
nameEQ (a,_) (b,_) = a == b
numberEQ (_,a) (_,b) = a == b
intEQ a b = a == b
member :: (a -> a -> Bool) -> a -> [a] -> Bool
I added:
member eq x ys | length ys < 1 = False
| head(ys) == x = True
| otherwise = member(x,tail(ys))
but i get errors about not being the correct type as well as some other stuff. We have to see if an element exists in from some type. So we have those 2 types above. Some examples given:
phoneDB = [("Jenny","867-5309"), ("Alice","555-1212"), ("Bob","621-6613")]
> member nameEQ ("Alice","") phoneDB
True
> member nameEQ ("Jenny","") phoneDB
True
> member nameEQ ("Erica","") phoneDB
False
> member numberEQ ("","867-5309") phoneDB
True
> member numberEQ ("","111-2222") phoneDB
False
> member intEQ 4 [1,2,3,4]
True
> member intEQ 4 [1,2,3,5]
False
not exactly sure what i need to do here. Any help or documentation on this would be great. Thanks!
Various things (I'm not going to write out the full answer as this is homework):
length ys < 1 can be more simply expressed as null ys
You don't need brackets around function arguments. head(ys) is more commonly written as head ys
You can, if you want, turn the top case and the other two into pattern matches rather than guards. member eq x [] = ... will match the empty case, member eq x (y:ys) = ... will match the non-empty case.
You are using == for comparison. But you're meant to use the eq function you're given instead.
You are bracketing the arguments to member as if this was Java or similar. In Haskell, arguments are separated by spaces, so member(x,(tail(ys)) should be member x (tail ys).
Those errors you gloss over "about not being the correct type as well as some other stuff" are important. They tell you what's wrong.
For example, the first time I threw your code into ghc I got:
Couldn't match expected type `a -> a -> Bool'
against inferred type `(a1, [a1])'
In the first argument of `member', namely `(x, tail (ys))'
In the expression: member (x, tail (ys))
In the definition of `member':
member eq x ys
| length ys < 1 = False
| head (ys) == x = True
| otherwise = member (x, tail (ys))
Well, when I look at it that's straightforward - you've typed
member(x,tail(ys))
When you clearly meant:
member x (tail ys)
Commas mean something in Haskell you didn't intend there.
Once I made that change it complained again that you'd left off the eq argument to member.
The error after that is tougher if you haven't learned about Haskell typeclasses yet, but suffice it to say that you need to use the passed-in eq function for comparing, not ==.
Since the parameters a in member :: (a -> a -> Bool) -> a -> [a] -> Bool
don't derive Eq, you can't use == to compare them,
but instead have to use the given function eq.
Therefore your code might look like this:
member :: (a -> a -> Bool) -> a -> [a] -> Bool
member eq x ys
| length ys < 1 = False
| eq x (head ys) = True
| otherwise = member eq x (tail ys)
Only problem with this is, that length still requires to evaluate the entire List,
so you could reach a a better performance writing:
member' :: (a -> a -> Bool) -> a -> [a] -> Bool
member' eq x (y:ys)
| eq x y = True
| otherwise = member' eq x ys
member' _ _ [] = False
With the use of any you can simplify it even more:
member'' :: (a -> a -> Bool) -> a -> [a] -> Bool
member'' f a = any (f a)

Resources