-
Notifications
You must be signed in to change notification settings - Fork 1
/
TreeToFormula.hs
162 lines (121 loc) · 5.92 KB
/
TreeToFormula.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}
module LogicTasks.Syntax.TreeToFormula where
import Control.Monad.IO.Class(MonadIO (liftIO))
import Control.OutputCapable.Blocks (
GenericOutputCapable (..),
LangM,
OutputCapable,
($=<<),
english,
german,
)
import Data.ByteString.Lazy.UTF8 (fromString)
import Data.Digest.Pure.SHA (sha1, showDigest)
import Data.Maybe (fromJust, isNothing)
import Image.LaTeX.Render (FormulaOptions(..), SVG, defaultEnv, imageForFormula)
import LogicTasks.Helpers (cacheIO, extra, instruct, keyHeading, reject, example, basicOpKey, arrowsKey)
import Tasks.SynTree.Config (checkSynTreeConfig, SynTreeConfig)
import Trees.Types (TreeFormulaAnswer(..))
import Formula.Util (isSemanticEqual)
import Control.Monad (when)
import Trees.Print (transferToPicture)
import Tasks.TreeToFormula.Config (TreeToFormulaInst(..))
import Formula.Parsing.Delayed (Delayed, withDelayedSucceeding, parseDelayedWithAndThen, complainAboutMissingParenthesesIfNotFailingOn)
import Formula.Parsing (Parse(..))
import Trees.Parsing()
import UniversalParser (logicToken)
import Text.Parsec (many)
import Data.Functor (void)
import Formula.Types (Formula(atomics))
import Data.List ((\\), intercalate)
import Data.List.Extra (notNull)
description :: (OutputCapable m, MonadIO m) => FilePath -> TreeToFormulaInst -> LangM m
description path TreeToFormulaInst{..} = do
instruct $ do
english "Consider the following syntax tree:"
german "Betrachten Sie den folgenden Syntaxbaum:"
image $=<< liftIO $ cacheTree latexImage path
instruct $ do
english "Give the propositional logic formula that is represented by this syntax tree."
german "Geben Sie die aussagenlogische Formel an, die von diesem Syntaxbaum dargestellt wird."
instruct $ do
english "(You are allowed to add arbitrarily many additional pairs of brackets.)"
german "(Dabei dürfen Sie beliebig viele zusätzliche Klammerpaare hinzufügen.)"
when addExtraHintsOnSemanticEquivalence $ instruct $ do
english "Remarks: The exact formula of the syntax tree must be specified. Other formulas that are semantically equivalent to this formula are incorrect solutions! You are also not allowed to use associativity in this task in order to save brackets."
german "Hinweise: Es muss die exakte Formel des Syntaxbaums angegeben werden. Andere, selbst zu dieser Formel semantisch äquivalente Formeln sind keine korrekte Lösung! Auch dürfen Sie bei dieser Aufgabe nicht Assoziativität verwenden, um Klammern einzusparen."
keyHeading
basicOpKey unicodeAllowed
when showArrowOperators arrowsKey
extra addText
pure ()
verifyInst :: OutputCapable m => TreeToFormulaInst -> LangM m
verifyInst _ = pure ()
verifyConfig :: OutputCapable m => SynTreeConfig -> LangM m
verifyConfig = checkSynTreeConfig
start :: TreeFormulaAnswer
start = TreeFormulaAnswer Nothing
partialGrade :: OutputCapable m => TreeToFormulaInst -> Delayed TreeFormulaAnswer -> LangM m
partialGrade = parseDelayedWithAndThen parser complainAboutMissingParenthesesIfNotFailingOn (void $ many logicToken) . partialGrade'
partialGrade' :: OutputCapable m => TreeToFormulaInst -> TreeFormulaAnswer -> LangM m
partialGrade' inst sol
| isNothing $ maybeTree sol = reject $ do
english "You did not submit a solution."
german "Die Abgabe ist leer."
| notNull atomicsDiff = reject $ do
english $ "Your solution contains unknown atomic formulas: " ++ diffDisplay
german $ "Die Abgabe enthält unbekannte atomare Formeln: " ++ diffDisplay
| otherwise = pure ()
where treeAtomics = atomics $ tree inst
solTreeAtomics = atomics $ fromJust $ maybeTree sol
atomicsDiff = solTreeAtomics \\ treeAtomics
diffDisplay = intercalate ", " (map show atomicsDiff)
completeGrade
:: (OutputCapable m, MonadIO m)
=> FilePath
-> TreeToFormulaInst
-> Delayed TreeFormulaAnswer
-> LangM m
completeGrade path inst = completeGrade' path inst `withDelayedSucceeding` parser
completeGrade'
:: (OutputCapable m, MonadIO m)
=> FilePath
-> TreeToFormulaInst
-> TreeFormulaAnswer
-> LangM m
completeGrade' path inst sol
| treeAnswer /= correctTree = refuse $ do
instruct $ do
english "Your solution is not correct. The syntax tree for your entered formula looks like this:"
german "Ihre Abgabe ist nicht die korrekte Lösung. Der Syntaxbaum zu Ihrer eingegebenen Formel sieht so aus:"
image $=<< liftIO $ cacheTree (transferToPicture treeAnswer) path
when (addExtraHintsOnSemanticEquivalence inst && isSemanticEqual treeAnswer correctTree) $
instruct $ do
english "This syntax tree is semantically equivalent to the original one, but not identical."
german "Dieser Syntaxbaum ist semantisch äquivalent zum ursprünglich gegebenen, aber nicht identisch."
when (showSolution inst) $
example (correct inst) $ do
english "A possible solution for this task is:"
german "Eine mögliche Lösung für die Aufgabe ist:"
pure ()
| otherwise = pure ()
where treeAnswer = fromJust (maybeTree sol)
correctTree = tree inst
treeOptions :: FormulaOptions
treeOptions = FormulaOptions "\\usepackage[linguistics]{forest}" Nothing
getImage :: String -> IO SVG
getImage s = do
let iTree = "\\begin{forest}" ++ s ++ "\\end{forest}"
render <- imageForFormula defaultEnv treeOptions iTree
case render of (Left err) -> error $ unlines ["failed to render an image with the given formula: ", show err]
(Right svg) -> pure svg
outputImage :: FilePath -> String -> IO FilePath
outputImage path tree = do
picture <- getImage tree
writeFile path picture
pure path
cacheTree :: String -> FilePath -> IO FilePath
cacheTree tree path = cacheIO path ext "tree-" tree outputImage
where ext = showDigest (sha1 . fromString $ tree) ++ ".svg"