summaryrefslogtreecommitdiff
path: root/assignment-4/student.icl
blob: 2daff18d2d4aa4e89e2bd7f89d2ad16482176fbb (plain) (blame)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
module student

// Laurens Kuiper (s4467299)
// Camil Staps (s4498062)

// Example output:
// Your first name please: Camil
// Your last name please: Staps
// Your student number please: 4498062
// {Student|fname=Camil,lname=Staps,snum=4498062}

import StdEnv, StdMaybe, monad
/*
 * Pieter Koopman, pieter@cs.ru.nl
 * Advanced Programming, week 4
 */

// ---- an IO monad with maybe results --- //

:: *State = {w :: *World, c :: *Maybe *File}
:: IO a = IO (State -> *(Maybe a, State))

open :: State -> State
open {w, c=Nothing}
	# (console, w) = stdio w
	= {w = w, c = Just console}
open s = s

close :: State -> State
close { w, c=Just f} = { w = snd (fclose f w), c = Nothing}
close s = s

unIO :: (IO a) -> State -> *(Maybe a, State)
unIO (IO f) = f

run :: (IO a) *World -> *World
run m w = (close (snd (unIO m {w=w, c=Nothing}))).w

// ---- reading from console --- //

class read a :: IO a

instance read String where
	read = IO r where
		r s
		#! {w,c=Just c} = open s
		   (line, c) = freadline c
		   s = rmNL line
		| size s > 0
			= (Just s,{w = w, c = Just c})
			#! c = c <<< "String must be not empty "
			   (line, c) = freadline c
			   s = rmNL line
			| size s > 0
				= (Just s,  {w = w, c = Just c})
				= (Nothing, {w = w, c = Just c})

instance read Int where
	read = IO r where
		r s
		#! {w,c=Just c} = open s
		   (b,i,c) = freadi c
		| b
		= (Just i, {w = w, c = Just c})
		#! (_, c) = freadline c
		   c = c <<< "An integer please "
		   (b,i,c) = freadi c
		| b
		= (Just i,  {w = w, c = Just c})
		#! (_, c) = freadline c
		= (Nothing, {w = w, c = Just c})

write :: String -> IO String
write mess = IO w where
	w s
	#! {w,c=Just c} = open s
	= (Just mess,{w=w,c=Just (c <<< mess)})

// ---- make IO a monad --- //

instance Functor IO where
	fmap f (IO g)
		= IO \s.case g s of
					(Just a, s) = (Just (f a),s)
					(Nothing,s) = (Nothing  , s)

instance Applicative IO where
	pure a = IO \s.(Just a, s)
	(<*>) (IO f) (IO g) = IO \s.case f s of
		(Just f,s) = case g s of
			(Just a,s) = (Just (f a),s)
			(n,     s) = (Nothing, s)
		(n,     s) = (Nothing, s)

instance Monad IO where
	bind (IO f) g = IO \s.case f s of
		(Just a, s) = unIO (g a) s
		(n,      s) = (Nothing, s)

instance fail IO where fail = IO \s.(Nothing,s)

instance OrMonad IO where
	<|> (IO f) (IO g) =
		IO \s.case f s of
			(Nothing, s) = g s
			other        = other

// ---- reading a student record --- //

Start w = run (f3 >>= write o toString <|> write "Failed\n") w

:: Student =
  { fname :: String
  , lname :: String
  , snum  :: Int
  }

instance toString Student where
	toString {fname,lname,snum} = "{Student|fname=" + fname + ",lname=" + lname + ",snum=" + toString snum + "}"
instance + String where + s t = s +++ t

f0 :: *World -> (Student, *World)
f0 world = ({fname = rmNL fname, lname = rmNL lname, snum = snum}, world2) where
	(console1, world1) = stdio world
	console2 = console1 <<< "Your first name please: "
	(fname,console3) = freadline console2
	console4 = console3 <<< "Your last name please: "
	(lname,console5) = freadline console4
	console6 = console5 <<< "Your student nmber please: "
	(b1,snum,console7) = freadi console6
	(b2, world2) = fclose console7 world1

f1 :: *World -> (Student, *World)
f1 world
#! (console, world) = stdio world
   console = console <<< "Your first name please: "
   (fname,console) = freadline console
   console = console <<< "Your last name please: "
   (lname,console) = freadline console
   console = console <<< "Your student nmber please: "
   (b1,snum,console) = freadi console
   (b2, world) = fclose console world
= ({fname = rmNL fname, lname = rmNL lname, snum = snum}, world)

f2 :: IO String
f2
	= (        write "Your first name please: "
	>>| read
	>>= \fname.write "Your last name please: "
	>>| read
	>>= \lname.write "Your student nmber please: "
	>>| read
	>>= \snum. rtrn {fname = rmNL fname, lname = rmNL lname, snum = snum}
	>>= write o toString)
	<|> write "failed to read a student"

f3 :: IO Student
f3 =
	(\f l s -> {fname=rmNL f, lname=rmNL l, snum=s}) <$>
	input "Your first name please: " <*>
	input "Your last name please: " <*>
	input "Your student number please: "
where
	input :: String -> IO a | read a
	input s = write s *> read

	// It would really be much easier if we would use Platform from the start in this course.
	(*>) infixl 4 :: (f a) (f b) -> f b | Applicative f
	(*>) fa fb = id <$ fa <*> fb

	(<$) infixl 4 :: a (f b) -> f a | Functor f
	(<$) x fa = fmap (const x) fa

rmNL :: String -> String
rmNL string
  # len = size string
  | len > 0 && string.[len-1] == '\n'
    = string % (0, len - 2)
    = string