Skip to content

Commit 542135d

Browse files
committed
Switch to StateT
1 parent ff6d0eb commit 542135d

File tree

2 files changed

+65
-89
lines changed

2 files changed

+65
-89
lines changed

src/ZMidi/Internal/ParserMonad.fs

Lines changed: 28 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ namespace ZMidi.Internal
44
module ParserMonad =
55

66
open System.IO
7-
7+
open FSharpPlus
8+
open FSharpPlus.Data
89
open ZMidi.Internal.Utils
910

1011
/// Status is either OFF or the previous VoiceEvent * Channel.
@@ -87,8 +88,7 @@ module ParserMonad =
8788
#endif
8889
)
8990

90-
type ParserMonad<'a> =
91-
ParserMonad of (State -> Result<'a * State, ParseError> )
91+
type ParserMonad<'a> = StateT<State, Result<'a * State, ParseError>>
9292

9393
let nullOut = new StreamWriter(Stream.Null) :> TextWriter
9494
let mutable debug = false
@@ -101,7 +101,7 @@ module ParserMonad =
101101

102102
let inline private apply1 (parser : ParserMonad<'a>)
103103
(state : State) : Result<'a * State, ParseError> =
104-
let (ParserMonad fn) = parser
104+
let (StateT fn) = parser
105105
try
106106
let result = fn state
107107
let oldState = state
@@ -131,20 +131,20 @@ module ParserMonad =
131131
)
132132

133133
let inline mreturn (x:'a) : ParserMonad<'a> =
134-
ParserMonad <| fun st -> Ok (x, st)
134+
StateT <| fun st -> Ok (x, st)
135135

136136
let inline private bindM (parser : ParserMonad<'a>)
137137
(next : 'a -> ParserMonad<'b>) : ParserMonad<'b> =
138-
ParserMonad <| fun state ->
138+
StateT <| fun state ->
139139
match apply1 parser state with
140140
| Error msg -> Error msg
141141
| Ok (ans, st1) -> apply1 (next ans) st1
142142

143143
let mzero () : ParserMonad<'a> =
144-
ParserMonad <| fun state -> Error (mkParseError state (EOF "mzero"))
144+
StateT <| fun state -> Error (mkParseError state (EOF "mzero"))
145145

146146
let inline mplus (parser1 : ParserMonad<'a>) (parser2 : ParserMonad<'a>) : ParserMonad<'a> =
147-
ParserMonad <| fun state ->
147+
StateT <| fun state ->
148148
match apply1 parser1 state with
149149
| Error _ -> apply1 parser2 state
150150
| Ok res -> Ok res
@@ -158,31 +158,6 @@ module ParserMonad =
158158
let (>>=) (m: ParserMonad<'a>) (k: 'a -> ParserMonad<'b>) : ParserMonad<'b> =
159159
bindM m k
160160

161-
type ParserBuilder() =
162-
member inline self.ReturnFrom (ma:ParserMonad<'a>) : ParserMonad<'a> = ma
163-
member inline self.Return x = mreturn x
164-
member inline self.Bind (p,f) = bindM p f
165-
member inline self.Zero a = ParserMonad (fun state -> Ok(a, state))
166-
//member self.Combine (ma, mb) = ma >>= mb
167-
168-
// inspired from http://www.fssnip.net/7UJ/title/ResultBuilder-Computational-Expression
169-
// probably broken
170-
member inline self.TryFinally(m, compensation) =
171-
try self.ReturnFrom(m)
172-
finally compensation()
173-
174-
//member self.Delay(f: unit -> ParserMonad<'a>) : ParserMonad<'a> = f ()
175-
//member self.Using(res:#System.IDisposable, body) =
176-
// self.TryFinally(body res, fun () -> if not (isNull res) then res.Dispose())
177-
//member self.While(guard, f) =
178-
// if not (guard()) then self.Zero () else
179-
// do f() |> ignore
180-
// self.While(guard, f)
181-
//member self.For(sequence:seq<_>, body) =
182-
// self.Using(sequence.GetEnumerator(), fun enum -> self.While(enum.MoveNext, fun () -> self.Delay(fun () -> body enum.Current)))
183-
184-
let (parseMidi:ParserBuilder) = new ParserBuilder()
185-
186161
let runParser (ma:ParserMonad<'a>) input initialState =
187162
apply1 ma { initialState with Input = input}
188163
|> Result.map fst
@@ -194,11 +169,11 @@ module ParserMonad =
194169

195170
/// Throw a parse error
196171
let parseError (genMessage : Pos -> string) : ParserMonad<'a> =
197-
ParserMonad <| fun st -> Error (mkOtherParseError st genMessage)
172+
StateT <| fun st -> Error (mkOtherParseError st genMessage)
198173

199174
/// Run the parser, if it fails swap the error message.
200175
let inline ( <??> ) (parser : ParserMonad<'a>) (genMessage : Pos -> string) : ParserMonad<'a> =
201-
ParserMonad <| fun st ->
176+
StateT <| fun st ->
202177
match apply1 parser st with
203178
| Ok result -> Ok result
204179
| Error e ->
@@ -207,13 +182,13 @@ module ParserMonad =
207182

208183
///
209184
let fmap (f: 'a -> 'b) (p: ParserMonad<'a>) : ParserMonad<'b> =
210-
parseMidi {
185+
monad {
211186
let! a = p
212187
return (f a)
213188
}
214189
let inline ( <~> (* <$> *) ) (a) b = fmap a b
215190
let ( *> ) (a: ParserMonad<'a>) (b: 'a -> ParserMonad<'b>) : ParserMonad<'b> =
216-
parseMidi {
191+
monad {
217192
let! a = a
218193
return! (b a)
219194
}
@@ -240,16 +215,16 @@ module ParserMonad =
240215

241216

242217
let fatalError err =
243-
ParserMonad <| fun st -> Error (mkParseError st err)
218+
StateT <| fun st -> Error (mkParseError st err)
244219

245220
let getRunningEvent : ParserMonad<VoiceEvent> =
246-
ParserMonad <| fun st -> Ok (st.RunningStatus , st)
221+
StateT <| fun st -> Ok (st.RunningStatus , st)
247222

248223
let inline setRunningEvent (runningStatus : VoiceEvent) : ParserMonad<unit> =
249-
ParserMonad <| fun st -> Ok ((), { st with RunningStatus = runningStatus })
224+
StateT <| fun st -> Ok ((), { st with RunningStatus = runningStatus })
250225

251226
let getPos : ParserMonad<int> =
252-
ParserMonad <| fun st -> Ok (st.Position, st)
227+
StateT <| fun st -> Ok (st.Position, st)
253228

254229
let inline private (|PositionValid|PositionInvalid|) (input: MidiData, state: State) =
255230
if state.Position >= 0 && state.Position < input.Length then
@@ -258,7 +233,7 @@ module ParserMonad =
258233
PositionInvalid
259234

260235
let inline private checkedParseM (name: string) (f: State -> Result<('a * State), ParseError>) =
261-
ParserMonad
236+
StateT
262237
(fun state ->
263238
try
264239
match state.Input, state with
@@ -286,7 +261,7 @@ module ParserMonad =
286261
/// Repeats a given <see paramref="parser"/> <see paramref="length"/> times.
287262
/// Fails with accumulated errors when any encountered.
288263
let inline count (length : ^T) (parser : ParserMonad<'a>) : ParserMonad<'a []> =
289-
ParserMonad <| fun state ->
264+
StateT <| fun state ->
290265
let rec work (i : 'T)
291266
(st : State)
292267
(fk : ParseError -> Result<'a list * State, ParseError>)
@@ -305,7 +280,7 @@ module ParserMonad =
305280

306281
/// Run a parser within a bounded section of the input stream.
307282
let repeatTillPosition (maxPosition: Pos) (p: ParserMonad<'a>) : ParserMonad<'a array> =
308-
ParserMonad(fun state ->
283+
StateT(fun state ->
309284
let results = ResizeArray()
310285
let mutable firstError = Ok (Array.empty, state)
311286
let mutable lastState = state
@@ -328,7 +303,7 @@ module ParserMonad =
328303
)
329304

330305
let inline boundRepeat (n: ^T) (p: ParserMonad<'a>) : ParserMonad<'a array> =
331-
ParserMonad(fun state ->
306+
StateT (fun state ->
332307
let result = Array.zeroCreate (int n)
333308
let mutable lastState = state
334309
// revisit with a fold?
@@ -357,7 +332,7 @@ module ParserMonad =
357332
/// Apply the parser for /count/ times, derive the final answer
358333
/// from the intermediate list with the supplied function.
359334
let inline gencount (plen: ParserMonad<'T>) (p: ParserMonad<'a>) (constr: ^T -> 'a array -> 'answer) : ParserMonad<'answer> =
360-
parseMidi {
335+
monad {
361336
let! l = plen
362337
logf "gen count: l: %i" l
363338
let! items = boundRepeat l p
@@ -378,22 +353,22 @@ module ParserMonad =
378353

379354
/// Parse a single byte char.
380355
let readChar : ParserMonad<char> =
381-
parseMidi {
356+
monad {
382357
let! a = readByte
383358
return (char a)
384359
}
385360

386361
/// Parse a string of the given length.
387362
let readString (length : int) : ParserMonad<string> =
388-
parseMidi {
363+
monad {
389364
let! arr = count length readChar
390365
return (System.String arr)
391366
}
392367
<??> sprintf "readString failed at %i"
393368
open ZMidi.Internal.DataTypes.FromBytes
394369
/// Parse a uint16 (big endian).
395370
let readUInt16be : ParserMonad<uint16>=
396-
parseMidi {
371+
monad {
397372
let! a = readByte
398373
let! b = readByte
399374
return word16be a b
@@ -402,7 +377,7 @@ module ParserMonad =
402377

403378
/// Parse a word14 (big endian) from 2 consecutive bytes.
404379
let readWord14be =
405-
parseMidi {
380+
monad {
406381
let! a = readByte
407382
let! b = readByte
408383
return (word14be a b)
@@ -411,7 +386,7 @@ module ParserMonad =
411386

412387
/// Parse a word32 (big endian).
413388
let readUInt32be =
414-
parseMidi {
389+
monad {
415390
let! a = readByte
416391
let! b = readByte
417392
let! c = readByte
@@ -421,9 +396,9 @@ module ParserMonad =
421396

422397
/// Parse a word24 (big endian).
423398
let readWord24be =
424-
parseMidi {
399+
monad {
425400
let! a = readByte
426401
let! b = readByte
427402
let! c = readByte
428403
return (word24be a b c)
429-
}
404+
}

0 commit comments

Comments
 (0)