/
Solution.hs
131 lines (97 loc) · 3.02 KB
/
Solution.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
module Y2017.M07.D20.Solution where
import Prelude hiding (fail)
import Control.Monad hiding (fail)
-- below import available via 1HaskellADay git repository
import Relational.Scheme.Types
{--
So, yesterday, we did the types and parsers/readers for atomic values in our
Scheme DSL/Domain Specific Language, so the next logical step is to do lists
in Scheme?
Not according to the Reasoned Schemer. Their next step, before going into the
laws of fresh, (≡), and conde, is to play around with run* for awhile.
What is run*?
--}
data Fresh
data Expr = E ([Fresh] -> LogicValue)
data List
data Value = A Atom | L List
runx :: [Fresh] -> [Expr] -> [[Value]]
runx vars exprs = undefined
{--
Whoa. Wut?
Okay, I showed you the above, but we are NOT going to tackle that as today's
Haskell problem ...
... you're welcome ...
because we must first lay some groundwork to work our way up to run*, like:
* what is Fresh?
* how is an expression evaluated?
* what is a list? (it's own problem for a day)
* what is a value?
All that stuff.*
* stuff, n.: a technical term with a very specific meaning. "Stuff" means stuff.
But even before that, we need to know what #s and #u, the values of LogicValue,
signal to the run*-evaluator.
Fortunately, in Haskell, we have monads, so the meanings of #s and #u are
reductive:
#s: the evaluation of this expression is a success; the evaluation may proceed.
#u: the evaluation of this expression failed; the evaluation terminates.
Sounds familiar?
Define the evaluation of #s and #u monadically. Or, put another way, define
success and fail.
--}
runLogic :: MonadPlus m => LogicValue -> m ()
runLogic Success = guard (1 == 1)
runLogic Fail = guard (1 == 0)
{--
Inspired by Greg Weidman's C++-code:
#define true 1 == 1
#define false 1 == 0
Because you never can tell with C.
--}
success, fail :: MonadPlus m => m ()
success = runLogic Success
fail = runLogic Fail
-- note that fail here is equivalent to Prelude.fail "some error message"
{--
>>> fail :: [()]
[]
>>> success :: [()]
[()]
--}
{--
Great! We still have a long way to go before we define run*, but let's take
the next step. As Expr reduces to #s or #u, let's define runEvalExpr which
succeeds if all the evaluated expressions succeed and fails if any evaluated
expression fails. Now, again, we're not going to evaluate expressions until
we iron out some details, so let's simply provide the evaluated expressions
reduced to their LogicValue terms "by hand," as it were.
--}
runEvalExpr :: MonadPlus m => [LogicValue] -> m ()
runEvalExpr = reduce . map runLogic
reduce :: MonadPlus m => [m ()] -> m ()
reduce = foldr (>>) success
-- once defined, run against the following evaluated expressions
a, b, c :: [LogicValue]
a = replicate 5 Success
b = Fail : a
c = a ++ b
{--
>>> a
[#s,#s,#s,#s,#s]
>>> b
[#u,#s,#s,#s,#s,#s]
>>> c
[#s,#s,#s,#s,#s,#u,#s,#s,#s,#s,#s]
>>> runEvalExpr a :: [()]
[()]
>>> runEvalExpr b :: [()]
[]
>>> runEvalExpr c :: [()]
[]
>>> runEvalExpr a :: Maybe ()
Just ()
>>> runEvalExpr b :: Maybe ()
Nothing
>>> runEvalExpr c :: Maybe ()
Nothing
--}