Grammatical Framework: "linearization type field cannot be Int"; how to write a concrete syntax for grammar with arithmetic expressions? - gf

I'm trying to write a concrete syntax for this grammar (from Chapter 6 in Grammatical Framework: Programming with Multilingual Grammars):
abstract Arithm = {
flags startcat = Prop ;
cat
Prop ; -- proposition
Nat ; -- natural number
fun
Zero : Nat ; -- 0
Succ : Nat -> Nat ; -- the successor of x
Even : Nat -> Prop ; -- x is even
And : Prop -> Prop -> Prop ; -- A and B
}
There are predefined categories for integer, float and string literals (Int, Float and String), and they can be used as arguments to functions, but they may not be value types of any function.
In addition, they may not be used as a field in a linearisation type. This is what I would like to do, using plus defined in Predef.gf:
concrete ArithmEng of Arithm =
open Predef, SymbolicEng, SyntaxEng, ParadigmsEng in
lincat
Prop = S ;
Nat = {s : NP ; n : Int} ;
lin
Zero = mkNat 0 ;
Succ nat = let n' : Int = Predef.plus nat.n 1 in mkNat n' ;
Even nat = mkS (mkCl nat.s (mkA "even")) ;
And p q = mkS and_Conj p q ;
oper
mkNat : Int -> Nat ;
mkNat int = lin Nat {s = symb int ; n = int} ;
} ;
But of course, this does not work: I get the error "linearization type field cannot be Int".
Maybe the right answer to my question is to use another programming language, but I am curious, because this example is left as an exercise to the reader in the GF book, so I would expect it to be solvable.
I can write a unary solution, using the category Digits from Numeral.gf:
concrete ArithmEng of Arithm =
open SyntaxEng, ParadigmsEng, NumeralEng, SymbolicEng, Prelude in {
lincat
Prop = S ;
Nat = {s : NP ; d : Digits ; isZero : Bool} ;
lin
Zero = {s = mkNP (mkN "zero") ; d = IDig D_0 ; isZero = True} ;
Succ nat = case nat.isZero of {
True => mkNat (IDig D_1) ;
False => mkNat (IIDig D_1 nat.d) } ;
Even nat = mkS (mkCl nat.s (mkA "even")) ;
And p q = mkS and_Conj p q ;
oper
mkNat : Digits -> Nat ;
mkNat digs = lin Nat {s = symb (mkN "number") digs ; d = digs ; isZero = False} ;
} ;
This produces the following results:
Arithm> l -bind Even Zero
zero is even
0 msec
Arithm> l -bind Even (Succ Zero)
number 1 is even
0 msec
Arithm> l -bind Even (Succ (Succ (Succ Zero)))
number 111 is even
This is of course a possible answer, but I suspect this is not the way the exercise was intended to be solved. So I wonder if I'm missing something, or if the GF language used to support more operations on Ints?

A possible, but still rather unsatisfactory answer, is to use the parameter Ints n for any natural number n.
Notice the difference:
Int is a literal type, just like String and Float.
All literals have {s : Str} as their lincat in every concrete syntax, and you can't change it in any way.
Since the lincat contains Str (not String), you are not allowed to pattern match it at runtime.
Introducing Ints n: a parameter type
However, Ints n is a parameter type, because it's finite.
You may have seen Ints n in old RGL languages, like the following Finnish grammar:
-- from the Finnish resource grammar
oper
NForms : Type = Predef.Ints 10 => Str ;
nForms10 : (x1,_,_,_,_,_,_,_,_,x10 : Str) -> NForms =
\ukko,ukon,ukkoa,ukkona,ukkoon,
ukkojen,ukkoja,ukkoina,ukoissa,ukkoihin -> table {
0 => ukko ; 1 => ukon ; 2 => ukkoa ;
3 => ukkona ; 4 => ukkoon ; 5 => ukkojen ;
6 => ukkoja ; 7 => ukkoina ; 8 => ukoissa ;
9 => ukkoihin ; 10 => ukko
} ;
What's happening here? This is an inflection table, where the left-hand side is… just numbers, instead of combinations of case and number. (For instance, 5 corresponds to plural genitive. Yes, it is completely unreadable for anyone who didn't write that grammar.)
That same code could as well be written like this:
-- another way to write the example from the Finnish RG
param
NForm = SgNom | SgGen | … | PlGen | PlIll ; -- Named params instead of Ints 10
oper
NForms : Type = NForm => Str ;
nForms10 : (x1,_,_,_,_,_,_,_,_,x10 : Str) -> NForms =
\ukko,ukon,ukkoa,ukkona,ukkoon,
ukkojen,ukkoja,ukkoina,ukoissa,ukkoihin -> table {
SgNom => ukko ;
SgGen => ukon ;
...
PlGen => ukkojen ;
PlIll => ukkoihin
} ;
As you can see, the integer works as a left-hand side of a list: 5 => ukkojen is as valid GF as PlGen => ukkojen. In that particular case, 5 has the type Ints 10.
Anyway, that code was just to show you what Ints n is and how it's used in other grammars than mine, which I'll soon paste here.
Step 1: incrementing the Ints
Initially, I wanted to use Int as a field in my lincat for Nat. But now I will use Ints 100 instead. I linearise Zero as {n = 0}.
concrete ArithmC of Arithm = open Predef in {
lincat
Nat = {n : Ints 100} ;
lin
Zero = {n = 0} ; -- the 0 is of type Ints 100, not Int!
Now we linearise also Succ. And here's the exciting news: we can use Predef.plus on a runtime value, because the runtime value is no longer on Int, but Ints n---which is finite! So we can do this:
lin
Succ x = {n = myPlus1 ! x.n} ;
oper
-- We use Predef.plus on Ints 100, not Int
myPlus1 : Ints 100 => Ints 100 = table {
100 => 100 ; -- Without this line, we get error
n => Predef.plus n 1 -- magic!
} ;
}
As you can see from myPlus1, it's definitely possible to pattern match Ints n at runtime. And we can even use the Predef.plus on it, except that we must cap it at the highest value. Without the line 100 => 100, we get the following error:
- compiling ArithmC.gf... Internal error in GeneratePMCFG:
convertTbl: missing value 101
among 0
1
...
100
Unfortunately, it's restricted to a finite n.
Let's test this in the GF shell:
$ gf
…
> i -retain ArithmC.gf
> cc Zero
{n = 0; lock_Nat = <>}
> cc Succ Zero
{n = 1; lock_Nat = <>}
> cc Succ (Succ (Succ (Succ (Succ Zero))))
{n = 5; lock_Nat = <>}
Technically works, if you can say that. But we can't do anything interesting with it yet.
Step 2: Turn the Ints n into a NP
Previously, we just checked the values in a GF shell with cc (compute_concrete). But the whole task for the grammar was to produce sentences like "2 is even".
The lincat for Int (and all literal types) is {s : Str}. To make a literal into a NP, you can just use the Symbolic module.
But we cannot increment an Int at runtime, so we chose to use Ints 100 instead.
But there is no lincat for Ints n, because it's a param. So the only way I found is to manually define a showNat oper for Ints 100.
This is ugly, but technically it works.
concrete ArithmEng of Arithm =
open Predef, SymbolicEng, SyntaxEng, ParadigmsEng in {
lincat
Prop = S ;
Nat = {s : NP ; n : MyInts} ;
oper
MyInts = Ints 100 ;
lin
Zero = mkNat 0 ;
Succ nat = mkNat (myPlus1 ! nat.n) ;
Even nat = mkS (mkCl nat.s (mkA "even")) ;
And p q = mkS and_Conj p q ;
oper
mkNat : MyInts -> Nat ;
mkNat i = lin Nat {s = symb (showNat ! i) ; n = i} ;
myPlus1 : MyInts => MyInts = table {
100 => 100 ;
n => Predef.plus n 1
} ;
showNat : MyInts => Str ;
showNat = table {
0 => "0" ; 1 => "1" ; 2 => "2" ;
3 => "3" ; 4 => "4" ; 5 => "5" ;
6 => "6" ; 7 => "7" ; 8 => "8" ;
9 => "9" ; 10 => "10" ; 11 => "11" ;
12 => "12" ; 13 => "13" ; 14 => "14" ;
15 => "15" ; 16 => "16" ; 17 => "17" ;
18 => "18" ; 19 => "19" ; 20 => "20" ;
_ => "Too big number, I can't be bothered"
} ;
} ;
Let's test in the GF shell:
Arithm> gr | l -treebank
Arithm: Even (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))))))
ArithmEng: 12 is even
So yes, technically it works, but it's unsatisfactory. It only works for a finite n, and I had to type out a bunch of boilerplate in the showNat oper. I'm still unsure if this was the intended way by the GF book, or if GF used to support more operations on Int.
Other solutions
Here's a solution by daherb, where Zero outputs the string "0" and Succ outputs the string "+1", and the final output is evaluated in an external programming language.

Related

How to deal with "Error: Multiple solutions found"?

I'm trying to build a set datatype.
mutual
data Set : Type -> Type where
Nil : Eq a => Set a
(::) : Eq a => (x : a) -> (s : Set a) -> {auto _ : contains x s = False} -> Set a
contains : Eq a => a -> Set a -> Bool
contains x [] = False
contains x (y :: s) = (x == y) || contains x s
But I have no idea how to deal with this error:
Error: While processing right hand side of contains. Multiple solutions found in search of:
Eq a
test:9:26--9:32
5 | (::) : Eq a => (x : a) -> (s : Set a) -> {auto _ : contains x s = False} -> Set a
6 |
7 | contains : Eq a => a -> Set a -> Bool
8 | contains x [] = False
9 | contains x (y :: s) = (x == y) || contains x s
^^^^^^
Possible correct results:
conArg (implicitly bound at test:9:3--9:49)
conArg (implicitly bound at test:9:3--9:49)
You have multiple instances of Eq a floating around (one for each set element), so Idris isn't sure which one to use. For example, in contains, there's one from contains : Eq a => and another less obvious one from (y :: s). You can disambiguate with
contains : Eq a => a -> Set a -> Bool
contains x [] = False
contains #{eq} x (y :: s) = ((==) #{eq} x y) || contains #{eq} x s
though it may be better to work out some refactor that doesn't have multiple Eq a, if that's possible.

Conjunction for Verb Phrase on GF

Problem
I'm trying to generate the sentence It's sunny on Monday and rainy on Tuesday on GF using RGL. I looked for a method to generate this sentence on the RGL page, but I couldn't find anything that might help with this. Checked Extend.gf on GitHub for more information about GF, and I found these three lines:
MkVPS : Temp -> Pol -> VP -> VPS ; -- hasn't slept
ConjVPS : Conj -> [VPS] -> VPS ; -- has walked and won't sleep
PredVPS : NP -> VPS -> S ; -- she [has walked and won't sleep]
They seemed promising at first glance, but when I tried implementing them on a real code, it seems like I misused [VPS]. My code:
mkPhr(PredVPS
(it_NP)
(ConjVPS
(and_Conj)
(MkVPS
(mkTemp (futureTense) (simultaneousAnt))
(positivePol)
(mkVP
(mkVP (mkA "sunny"))
(SyntaxEng.mkAdv (on_Prep) (mkNP (mkN ("Monday"))))))
(MkVPS
(mkTemp (futureTense) (simultaneousAnt))
(positivePol)
(mkVP
(mkVP (mkA "rainy"))
(SyntaxEng.mkAdv (on_Prep) (mkNP (mkN ("Tuesday"))))))));
But I ran into this error, which obviously a problem with the defined variable and the expected one.
missing record fields: s1, s2 type of MkVPS (mkTemp futureTense simultaneousAnt) positivePol (AdvVP ((\a -> UseComp (CompAP (PositA a))) (regA "rainy")) (PrepNP on_Prep ((\n -> MassNP (UseN n)) (regN "Monday"))))
expected: {s1 : ResEng.Agr => Str; s2 : ResEng.Agr => Str}
inferred: {s : ResEng.Agr => Str; lock_VPS : {}}
Question
What is the correct way to use [VPS]?
Clarification on lists
Just like with other list categories C, you need to use a constructor that takes two (or more) Cs and creates a [C].
For categories that are in the RGL API, there are convenience opers of type mkC : Conj -> C -> C -> C, but under the hood, those opers also need to call the proper constructors for [C]. (The constructors are called BaseC and ConsC, and you can read more on lists here.)
How to use conjunctions with VPSs
So VPS is not in the API, so there is no convenience oper with type signature Conj -> VPS -> VPS -> VPS. Instead, you need to call BaseVPS explicitly. Here is working code, I cut your long expression into smaller pieces.
resource VPS = open SyntaxEng, ParadigmsEng, ExtendEng in {
oper
-- Lexicon
sunny_A : A = mkA "sunny" ;
rainy_A : A = mkA "rainy" ;
monday_N : N = mkN "Monday" ;
tuesday_N : N = mkN "Tuesday" ;
-- Helper functions
adj_on_day : A -> N -> VP = \a,n ->
mkVP (mkVP a) (SyntaxEng.mkAdv on_Prep (mkNP n)) ;
sunny_on_Monday_VP : VP = adj_on_day sunny_A monday_N ;
rainy_on_Tuesday_VP : VP = adj_on_day rainy_A tuesday_N ;
tenseVPS : Tense -> VP -> VPS = \tns,vp ->
MkVPS (mkTemp tns simultaneousAnt) positivePol vp ;
futureVPS = tenseVPS futureTense ;
pastVPS = tenseVPS pastTense ;
-- Constructing the phrase
-- lin: "it will be sunny on Monday and will be rainy on Tuesday"
futFutPhrase : Phr =
mkPhr (
PredVPS it_NP
(ConjVPS -- : Conj -> [VPS] -> VPS
and_Conj -- : Conj
(BaseVPS -- : VPS -> VPS -> [VPS]
(futureVPS sunny_on_Monday_VP) -- : VPS
(futureVPS rainy_on_Tuesday_VP) -- : VPS
)
)
) ;
-- lin: "it was sunny on Monday and will be rainy on Tuesday"
pastFutPhrase : Phr =
mkPhr (
PredVPS it_NP
(ConjVPS -- : Conj -> [VPS] -> VPS
and_Conj -- : Conj
(BaseVPS -- : VPS -> VPS -> [VPS]
(pastVPS sunny_on_Monday_VP) -- : VPS
(futureVPS rainy_on_Tuesday_VP) -- : VPS
)
)
) ;
}
And it works like this:
$ gf
Languages:
> i -retain VPS.gf
> cc -one futFutPhrase
it will be sunny on Monday and will be rainy on Tuesday
> cc -one pastFutPhrase
it was sunny on Monday and will be rainy on Tuesday
So the tenses are repeated in both cases, because the conjunction is on the VPS level, not on the AP level.
How to create the phrase you wanted
If you want to have ellipsis, "it will be sunny on Monday and rainy on Tuesday", you will need to attach the Adv "on Monday" to the AP "sunny" using AdvAP, then do an AP conjunction, turn that AP into VP, and then use that VP in a Cl as you normally would. Here is code, a separate file from the previous:
resource APConj = open SyntaxEng, ParadigmsEng, (A=AdjectiveEng) in {
oper
-- Lexicon
sunny_A : A = mkA "sunny" ;
rainy_A : A = mkA "rainy" ;
monday_N : N = mkN "Monday" ;
tuesday_N : N = mkN "Tuesday" ;
-- Helper functions
adj_on_day : A -> N -> AP = \a,n ->
A.AdvAP (mkAP a) (SyntaxEng.mkAdv on_Prep (mkNP n)) ;
sunny_on_Monday_AP : AP = adj_on_day sunny_A monday_N ;
rainy_on_Tuesday_AP : AP = adj_on_day rainy_A tuesday_N ;
-- Constructing the phrase
sunnyRainyEllipsisPhrase : Phr =
mkPhr (
mkCl (
mkVP (mkAP and_Conj sunny_on_Monday_AP rainy_on_Tuesday_AP)
)
) ;
}
Works like this:
$ gf
Languages:
> i -retain APConj.gf
> cc -one sunnyRainyEllipsisPhrase
it is sunny on Monday and rainy on Tuesday

How do I solve this ambiguous type variable error in Haskell?

I couldn't find an answer to my question among several ambiguous type variable error questions.
I'm currently trying to get this code I found to work. (https://gist.github.com/kirelagin/3886243)
My code:
import Control.Arrow
import Data.List
import qualified Data.Map as M
import Data.Function
main = do
putStrLn "Start test"
let foo = "Hello World"
let freqTest = freqList foo
putStrLn "Frequentie list"
print freqTest
putStrLn "Done.."
let treeTest = buildTree freqTest
putStrLn "Huffman Tree"
print treeTest
putStrLn "Done.."
let codeMaphTest = buildCodemap treeTest
putStrLn "Codemap ding"
-- print codeMaphTest
putStrLn "Done.."
--This typeclass is supposed to make life _a bit_ easier.
class Eq a => Bits a where
zer :: a
one :: a
instance Bits Int where
zer = 0
one = 1
instance Bits Bool where
zer = False
one = True
-- Codemap is generated from a Huffman tree. It is used for fast encoding.
type Codemap a = M.Map Char [a]
-- Huffman tree is a simple binary tree. Each leaf contains a Char and its weight.
-- Fork (node with children) also has weight = sum of weights of its children.
data HTree = Leaf Char Int
| Fork HTree HTree Int
deriving (Show)
weight :: HTree -> Int
weight (Leaf _ w) = w
weight (Fork _ _ w) = w
-- The only useful operation on Huffman trees is merging, that is we take
-- two trees and make them children of a new Fork-node.
merge t1 t2 = Fork t1 t2 (weight t1 + weight t2)
-- `freqList` is an utility function. It takes a string and produces a list
-- of pairs (character, number of occurences of this character in the string).
freqList :: String -> [(Char, Int)]
freqList = M.toList . M.fromListWith (+) . map (flip (,) 1)
-- `buildTree` builds a Huffman tree from a list of character frequencies
-- (obtained, for example, from `freqList` or elsewhere).
-- It sorts the list in ascending order by frequency, turns each (char, freq) pair
-- into a one-leaf tree and keeps merging two trees with the smallest frequencies
-- until only one tree is remaining.
buildTree :: [(Char, Int)] -> HTree
buildTree = bld . map (uncurry Leaf) . sortBy (compare `on` snd)
where bld (t:[]) = t
bld (a:b:cs) = bld $ insertBy (compare `on` weight) (merge a b) cs
-- The next function traverses a Huffman tree to obtain a list of codes for
-- all characters and converts this list into a `Map`.
buildCodemap :: Bits a => HTree -> Codemap a
buildCodemap = M.fromList . buildCodelist
where buildCodelist (Leaf c w) = [(c, [])]
buildCodelist (Fork l r w) = map (addBit zer) (buildCodelist l) ++ map (addBit one) (buildCodelist r)
where addBit b = second (b :)
-- Simple functions to get a Huffman tree or a `Codemap` from a `String`.
stringTree :: String -> HTree
stringTree = buildTree . freqList
stringCodemap :: Bits a => String -> Codemap a
stringCodemap = buildCodemap . stringTree
-- Time to do the real encoding and decoding!
-- Encoding function just represents each character of a string by corresponding
-- sequence of `Bit`s.
encode :: Bits a => Codemap a -> String -> [a]
encode m = concat . map (m M.!)
encode' :: Bits a => HTree -> String -> [a]
encode' t = encode $ buildCodemap t
-- Decoding is a little trickier. We have to traverse the tree until
-- we reach a leaf which means we've just finished reading a sequence
-- of `Bit`s corresponding to a single character.
-- We keep doing this to process the whole list of `Bit`s.
decode :: Bits a => HTree -> [a] -> String
decode tree = dcd tree
where dcd (Leaf c _) [] = [c]
dcd (Leaf c _) bs = c : dcd tree bs
dcd (Fork l r _) (b:bs) = dcd (if b == zer then l else r) bs
Output:
huffmancompress.hs:17:24: error:
* Ambiguous type variable `a0' arising from a use of `buildCodemap'
prevents the constraint `(Bits a0)' from being solved.
Relevant bindings include
codeMaphTest :: Codemap a0 (bound at huffmancompress.hs:17:9)
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Bits Bool -- Defined at huffmancompress.hs:35:10
instance Bits Int -- Defined at huffmancompress.hs:31:10
* In the expression: buildCodemap treeTest
In an equation for `codeMaphTest':
codeMaphTest = buildCodemap treeTest
In the expression:
do putStrLn "Start test"
let foo = "Hello World"
let freqTest = freqList foo
putStrLn "Frequentie list"
....
|
17 | let codeMaphTest = buildCodemap treeTest
| ^^^^^^^^^^^^^^^^^^^^^
I've tried serveral things I found on the internet but nothing worth mentioning to be honest.
Maybe any of you guys can help me out!
On line 17, where the error points you:
let codeMaphTest = buildCodemap treeTest
What type is codeMaphTest? Should it be Codemap Int? Or Codemap String? Or, perhaps, Codemap Bool? The function buildCodemap can return any type, as long as it has an instance of Bit. So what type should it be?
The compiler doesn't know. There is nowhere to glean this information from. It's ambiguous.
And this is exactly what the compiler is telling you: "ambiguous type variable".
One way to fix this is to provide a type annotation (exactly as the error message says, by the way):
let codeMaphTest :: Codemap Int = buildCodemap treeTest
Note that I chose Int just as an example, because I don't know which type you meant (I'm somewhat like the compiler in that respect). Please substitute your own type - the one you actually wanted there.
Your code is indeed ambiguous. buildCodemap treeTest has a polymorphic type Bits a => Codemap a, so it can be used as a Codemap Int, a Codemap Bool, or even as another type if you defines further instances of Bits.
This is not a problem, on its own, but later on you try to use this value (e.g., to print it), so we really need to pick a concrete type a.
You could pick a at the definition point:
let codeMaphTest :: Codemap Int
codeMaphTest = buildCodemap treeTest
Or, alternatively, you could choose a later on, where you use it
print (codeMaphTest :: Codemap Int)

Making strIndex total in Quick Search?

I am working on a version of the Quick Search string searching algorithm in Idris, and have come up with this:
quickSearch : (needle : String) ->
(haystack : String) ->
{auto lengths : (length needle) `LTE` (length haystack)} ->
Maybe Nat
quickSearch needle haystack = let n = length needle in
let h = length haystack in
go (makeBadShift needle) n (h - n)
where
go : (badShift : CharShift) ->
(n : Nat) ->
(last : Nat) ->
Maybe Nat
go badShift n last = go' 0
where
go' : Nat -> Maybe Nat
go' i = if i > last then Nothing
else if (substr i n haystack) == needle then Just i
else if i == last then Nothing
else let ch = strIndex haystack (cast (n + i)) in
let shift = lookupChar badShift ch in
go' (i + shift)
(lookupChar and makeBadShift are elsewhere.)
This works fine, but I wanted to make it more formally correct. To start with, it's not total due to the use of strIndex. It's not hard to create a total version of strIndex (either going through List Char or this:)
strIndex' : (str : String) ->
(n : Nat) ->
{auto ok : (n `LT` (Strings.length str))} ->
Char
strIndex' str n = assert_total $ prim__strIndex str (cast n)
but then I have to have a way of proving that (n + i) is less than h. (It is, because at that point i < h - n.)
If I directly replace the ">" and "==" with their proof-bearing cousins, I wind up looking at negations:
iNEQlast : (i = last) -> Void
and
iNGTlast : (S last) `LTE` i -> Void
which left me stumped.
On the other hand, I can reverse the conditions, ending up with
"quicksearch.idr" 115L, 4588C written
needle : String
haystack : String
lengths : LTE (fromIntegerNat (prim__zextInt_BigInt (prim_lenString needle))) (fromIntegerNat (prim__zextInt_BigInt (prim_lenString haystack)))
badShift : CharShift
n : Nat
h : Nat
nh : LTE n h
i : Nat
iLTlast : LTE (S i) (minus h n)
iLTElast : LTE i (minus h n)
--------------------------------------
go'_rhs_1 : Maybe Nat
but at this point I'm thoroughly confused and don't know how to go forward.
What is the best thing to do now?

Coq - fold and maps on record types

I had previously posted problems like the following, but have not yet found a solution. I am having a store (mapping) from a record type (with five members) to a string value. A fold with a function guarding on the three elements of the record and returns a mapping (string to string). I need to solve some lemmas like gsc_MapsTo_iff_right below.
The code may contain some awkward syntax (for example fold) as I am not expert of Coq. Sorry for that.
Thank you for your help.
Wilayat
Require String.
Record c_id : Type := build_c_id {
c_id_d : String.string;
c_id_p : String.string;
c_id_s : bool;
c_id_h : bool;
c_id_k : String.string
}.
Definition skey := String.string.
Definition st (elt:Type) := list (String.string * elt).
Variable elt : Type.
Parameter Sadd : skey -> String.string -> st String.string -> st String.string.
Parameter SMapsTo : skey -> String.string -> st String.string -> Prop.
Definition ckey := c_id.
Definition ct (e:Type) := list (ckey * elt).
Implicit Type cm: ct elt.
Parameter Cadd : ckey -> String.string -> ct String.string -> st String.string.
Parameter CMapsTo : ckey -> String.string -> ct String.string -> Prop.
Parameter elements : ct String.string -> list (ckey*String.string).
Fixpoint rec_fold {A : Type} (f: ckey -> String.string -> A -> A) (l : list (ckey * String.string)) (b: A) : A :=
match l with
| nil => b
| cons (k, v) t => f k v (rec_fold f t b)
end.
Fixpoint fold {A: Type} (f: ckey -> String.string -> A -> A)
(cm: ct String.string) (b:A) : A :=
rec_fold f (elements cm) b.
Parameter empty : st String.string.
Axiom str_dec : forall a b : String.string, {a = b} + {a <> b}.
Definition str_eqdec (a b: String.string):bool :=
if str_dec a b then true else false.
Notation "x =?= y" := (str_eqdec x y) (at level 30).
Definition andb (b1 b2:bool) : bool := if b1 then b2 else false.
Notation "x & y" := (andb x y) (at level 40).
Definition get_sc (d p: String.string) (ckm: ct String.string)
: st String.string :=
fold
(fun cki v zm => if d =?= cki.(c_id_d) &
p =?= cki.(c_id_p) &
(negb (cki.(c_id_s)))
then Sadd cki.(c_id_k) v zm
else zm )
ckm
empty.
Lemma gsc_MapsTo_iff_right:
forall p d zk zv zh cm,
CMapsTo (build_c_id d p false zh zk) zv cm ->
SMapsTo zk zv (get_sc d p cm).
Proof.
Admitted.