diff --git a/examples/model/Lex.gf b/examples/model/Lex.gf new file mode 100644 index 000000000..61ba2586c --- /dev/null +++ b/examples/model/Lex.gf @@ -0,0 +1,8 @@ +interface Lex = open Grammar in { + + oper + even_A : A ; + odd_A : A ; + zero_PN : PN ; + +} \ No newline at end of file diff --git a/examples/model/LexEng.gf b/examples/model/LexEng.gf new file mode 100644 index 000000000..4808557ef --- /dev/null +++ b/examples/model/LexEng.gf @@ -0,0 +1,8 @@ +instance LexEng of Lex = open GrammarEng, ParadigmsEng in { + + oper + even_A = regA "even" ; + odd_A = regA "odd" ; + zero_PN = regPN "zero" ; + +} diff --git a/examples/model/LexFre.gf b/examples/model/LexFre.gf new file mode 100644 index 000000000..6b439f9b8 --- /dev/null +++ b/examples/model/LexFre.gf @@ -0,0 +1,8 @@ +instance LexFre of Lex = open GrammarFre, ParadigmsFre in { + + oper + even_A = regA "pair" ; + odd_A = regA "impair" ; + zero_PN = regPN "zéro" ; + +} diff --git a/examples/model/Makefile b/examples/model/Makefile new file mode 100644 index 000000000..e551142ac --- /dev/null +++ b/examples/model/Makefile @@ -0,0 +1,17 @@ +all: gf hs run + +gf: + echo "pm | wf math.gfcm" | gf MathEng.gf MathFre.gf + +hs: gf + echo "pg -printer=haskell | wf GSyntax.hs" | gf math.gfcm + +run: hs + ghc --make -o math Run.hs + +clean: + rm -f *.gfc *.gfr *.o *.hi + +distclean: + rm -f GSyntax.hs math math.gfcm *.gfc *.gfr *.o *.hi + diff --git a/examples/model/Math.gf b/examples/model/Math.gf new file mode 100644 index 000000000..036cab294 --- /dev/null +++ b/examples/model/Math.gf @@ -0,0 +1,11 @@ +abstract Math = { + + cat Prop ; Elem ; + + fun + And : Prop -> Prop -> Prop ; + Even : Elem -> Prop ; + Odd : Elem -> Prop ; + Zero : Elem ; + +} diff --git a/examples/model/MathEng.gf b/examples/model/MathEng.gf new file mode 100644 index 000000000..fcba8851b --- /dev/null +++ b/examples/model/MathEng.gf @@ -0,0 +1,7 @@ +--# -path=.:api:present:prelude:mathematical + +concrete MathEng of Math = MathI with + (Grammar = GrammarEng), + (Combinators = CombinatorsEng), + (Predication = PredicationEng), + (Lex = LexEng) ; diff --git a/examples/model/MathFre.gf b/examples/model/MathFre.gf new file mode 100644 index 000000000..87575ba06 --- /dev/null +++ b/examples/model/MathFre.gf @@ -0,0 +1,7 @@ +--# -path=.:api:present:prelude:mathematical + +concrete MathFre of Math = MathI with + (Grammar = GrammarFre), + (Combinators = CombinatorsFre), + (Predication = PredicationFre), + (Lex = LexFre) ; diff --git a/examples/model/MathI.gf b/examples/model/MathI.gf new file mode 100644 index 000000000..7acf0f895 --- /dev/null +++ b/examples/model/MathI.gf @@ -0,0 +1,16 @@ +incomplete concrete MathI of Math = + open Grammar, Combinators, Predication, Lex in { + + flags startcat = Prop ; + + lincat + Prop = S ; + Elem = NP ; + + lin + And x y = coord and_Conj x y ; + Even x = PosCl (pred even_A x) ; + Odd x = PosCl (pred odd_A x) ; + Zero = UsePN zero_PN ; + +} diff --git a/examples/model/Run.hs b/examples/model/Run.hs new file mode 100644 index 000000000..fa0cc8792 --- /dev/null +++ b/examples/model/Run.hs @@ -0,0 +1,33 @@ +module Main where + +import GSyntax +import GF.Embed.EmbedAPI + +main :: IO () +main = do + gr <- file2grammar "math.gfcm" + loop gr + +loop :: MultiGrammar -> IO () +loop gr = do + s <- getLine + interpret gr s + loop gr + +interpret :: MultiGrammar -> String -> IO () +interpret gr s = do + let tss = parseAll gr "Prop" s + case (concat tss) of + [] -> putStrLn "no parse" + t:_ -> print $ answer $ fg t + +answer :: GProp -> Bool +answer p = case p of + (GOdd x1) -> odd (value x1) + (GEven x1) -> even (value x1) + (GAnd x1 x2) -> answer x1 && answer x2 + +value :: GElem -> Int +value e = case e of + GZero -> 0 + diff --git a/examples/model/model-resource-app.html b/examples/model/model-resource-app.html new file mode 100644 index 000000000..a9edfc44b --- /dev/null +++ b/examples/model/model-resource-app.html @@ -0,0 +1,382 @@ + + +
+ ++In this directory, we have a minimal resource grammar +application whose architecture scales up to much +larger applications. The application is run from the +shell by the command +
++ math ++
+whereafter it reads user input in English and French. +To each input line, it answers by the truth value of +the sentence. +
++ ./math + zéro est pair + True + zero is odd + False + zero is even and zero is odd + False ++
+The source of the application consists of the following +files: +
++ LexEng.gf -- English instance of Lex + LexFre.gf -- French instance of Lex + Lex.gf -- lexicon interface + Makefile -- a makefile + MathEng.gf -- English instantiation of MathI + MathFre.gf -- French instantiation of MathI + Math.gf -- abstract syntax + MathI.gf -- concrete syntax functor for Math + Run.hs -- Haskell Main module ++
+The system was built in 22 steps explained below. +
+ +
+1. Write Math.gf, which defines what you want to say.
+
+ abstract Math = {
+
+ cat Prop ; Elem ;
+
+ fun
+ And : Prop -> Prop -> Prop ;
+ Even : Elem -> Prop ;
+ Zero : Elem ;
+
+ }
+
+
+2. Write Lex.gf, which defines which language-dependent
+parts are needed in the concrete syntax. These are mostly
+words (lexicon), but can in fact be any operations. The definitions
+only use resource abstract syntax, which is opened.
+
+ interface Lex = open Grammar in {
+
+ oper
+ even_A : A ;
+ zero_PN : PN ;
+
+ }
+
+
+3. Write LexEng.gf, the English implementation of Lex.gf
+This module uses English resource libraries.
+
+ instance LexEng of Lex = open GrammarEng, ParadigmsEng in {
+
+ oper
+ even_A = regA "even" ;
+ zero_PN = regPN "zero" ;
+
+ }
+
+
+4. Write MathI.gf, a language-independent concrete syntax of
+Math.gf. It opens interfaces can resource abstract syntaxes,
+which makes it an incomplete module, aka. parametrized module, aka.
+functor.
+
+ incomplete concrete MathI of Math =
+ open Grammar, Combinators, Predication, Lex in {
+
+ flags startcat = Prop ;
+
+ lincat
+ Prop = S ;
+ Elem = NP ;
+
+ lin
+ And x y = coord and_Conj x y ;
+ Even x = PosCl (pred even_A x) ;
+ Zero = UsePN zero_PN ;
+ }
+
+
+5. Write MathEng.gf, which is just an instatiation of MathI.gf,
+replacing the interfaces by their English instances. This is the module
+that will be used as a top module in GF, so it contains a path to
+the libraries.
+
+ --# -path=.:api:present:prelude:mathematical + + concrete MathEng of Math = MathI with + (Grammar = GrammarEng), + (Combinators = CombinatorsEng), + (Predication = PredicationEng), + (Lex = LexEng) ; ++ + +
+6. Test the grammar in GF by random generation and parsing. +
++ $ gf + > i MathEng.gf + > gr -tr | l -tr | p + And (Even Zero) (Even Zero) + zero is evenand zero is even + And (Even Zero) (Even Zero) ++
+When importing the grammar, you will fail if you haven't +
+GF_LIB_PATH as GF/lib
+make in GF/lib/resource-1.0
+
+7. Now it is time to add a new language. Write a French lexicon LexFre.gf:
+
+ instance LexFre of Lex = open GrammarFre, ParadigmsFre in {
+
+ oper
+ even_A = regA "pair" ;
+ zero_PN = regPN "zéro" ;
+ }
+
+
+8. You also need a French concrete syntax, MathFre.gf:
+
+ --# -path=.:api:present:prelude:mathematical + + concrete MathFre of Math = MathI with + (Grammar = GrammarFre), + (Combinators = CombinatorsFre), + (Predication = PredicationFre), + (Lex = LexFre) ; ++
+9. This time, you can test multilingual generation: +
++ > i MathFre.gf + > gr -tr | l -multi + Even Zero + zéro est pair + zero is even ++ + +
+10. You want to add a predicate saying that a number is odd.
+It is first added to Math.gf:
+
+ fun Odd : Elem -> Prop ; ++
+11. You need a new word in Lex.gf.
+
+ oper odd_A : A ; ++
+12. Then you can give a language-independent concrete syntax in
+MathI.gf:
+
+ lin Odd x = PosCl (pred odd_A x) ; ++
+13. The new word is implemented in LexEng.gf.
+
+ oper odd_A = regA "odd" ; ++
+14. The new word is implemented in LexFre.gf.
+
+ oper odd_A = regA "impair" ; ++
+15. Now you can test with the extended lexicon. First empty +the environment to get rid of the old abstract syntax, then +import the new versions of the grammars. +
++ > e + > i MathEng.gf + > i MathFre.gf + > gr -tr | l -multi + And (Odd Zero) (Even Zero) + zéro est impair et zéro est pair + zero is odd and zero is even ++ + +
+16. Your grammar is going to be used by persons whMathEng.gfo do not need
+to compile it again. They may not have access to the resource library,
+either. Therefore it is advisable to produce a multilingual grammar
+package in a single file. We call this package math.gfcm and
+produce it, when we have MathEng.gf and
+MathEng.gf in the GF state, by the command
+
+ > pm | wf math.gfcm ++ + +
+17. Write the Haskell main file Run.hs. It uses the EmbeddedAPI
+module defining some basic functionalities such as parsing.
+The answer is produced by an interpreter of trees returned by the parser.
+
+ module Main where + + import GSyntax + import GF.Embed.EmbedAPI + + main :: IO () + main = do + gr <- file2grammar "math.gfcm" + loop gr + + loop :: MultiGrammar -> IO () + loop gr = do + s <- getLine + interpret gr s + loop gr + + interpret :: MultiGrammar -> String -> IO () + interpret gr s = do + let tss = parseAll gr "Prop" s + case (concat tss) of + [] -> putStrLn "no parse" + t:_ -> print $ answer $ fg t + + answer :: GProp -> Bool + answer p = case p of + (GOdd x1) -> odd (value x1) + (GEven x1) -> even (value x1) + (GAnd x1 x2) -> answer x1 && answer x2 + + value :: GElem -> Int + value e = case e of + GZero -> 0 ++ +
+18. The syntax trees manipulated by the interpreter are not raw
+GF trees, but objects of the Haskell datatype GProp.
+From any GF grammar, a file GFSyntax.hs with
+datatypes corresponding to its abstract
+syntax can be produced by the command
+
+ > pg -printer=haskell | wf GSyntax.hs ++
+The module also defines the overloaded functions
+gf and fg for translating from these types to
+raw trees and back.
+
+19. Before compiling Run.hs, you must check that the
+embedded GF modules are found. The easiest way to do this
+is by two symbolic links to your GF source directories:
+
+ $ ln -s /home/aarne/GF/src/GF + $ ln -s /home/aarne/GF/src/Transfer/ ++ +
+20. Now you can run the GHC Haskell compiler to produce the program. +
++ $ ghc --make -o math Run.hs ++
+The program can be tested with the command ./math.
+
+21. For a stand-alone binary-only distribution, only
+the two files math and math.gfcm are needed.
+For a source distribution, the files mentioned in
+the beginning of this documents are needed.
+
+22. As a part of the source distribution, a Makefile is
+essential. The Makefile is also useful when developing the
+application. It should always be possible to build an executable
+from source by typing make.
+