Combining terminal and non-terminal errors
One feature of programming with "two-track" data is that once a value is on the failure track operations against it may be skipped if they expect a value on the passing track. However, this is not always the desired behavior. In many cases, we will want to perform mulitple operations on a value and record any unusual or interesting results, but still keep thing on the passing track. One obvious scenario is when we want to validate multiple pieces of input (such as might be received from an HTTP request).
1: 2: 3: 4: |
|
Given some aggregate user-supplied data, we want to check each datum.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: |
|
Now we can combine our individual checks, returning the original value along-side any issues.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: |
|
|
We can also mixed warnings in with operations that are terminal. In other words, we can still build workflows where certain operations switch the data over to the failure track.
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: |
|
|
In effect, we've turned "two-track" data into "three-track" data. But we can also flip this around. That's is, run operations over the data accumlating warnings. Then at the end, if we have any messages at all, switch to the failure track.
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: |
|
|
{FullName: string * string;
DateOfBirth: DateTime;
FavoriteColor: Color option;}
Full name: Pass-warn-fail.Applicant
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
type DateTime =
struct
new : ticks:int64 -> DateTime + 10 overloads
member Add : value:TimeSpan -> DateTime
member AddDays : value:float -> DateTime
member AddHours : value:float -> DateTime
member AddMilliseconds : value:float -> DateTime
member AddMinutes : value:float -> DateTime
member AddMonths : months:int -> DateTime
member AddSeconds : value:float -> DateTime
member AddTicks : value:int64 -> DateTime
member AddYears : value:int -> DateTime
...
end
Full name: System.DateTime
--------------------
DateTime()
(+0 other overloads)
DateTime(ticks: int64) : unit
(+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
(+0 other overloads)
struct
member A : byte
member B : byte
member Equals : obj:obj -> bool
member G : byte
member GetBrightness : unit -> float32
member GetHashCode : unit -> int
member GetHue : unit -> float32
member GetSaturation : unit -> float32
member IsEmpty : bool
member IsKnownColor : bool
...
end
Full name: System.Drawing.Color
Full name: Microsoft.FSharp.Core.option<_>
Full name: Pass-warn-fail.checkName
type String =
new : value:char -> string + 7 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 2 overloads
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
member GetHashCode : unit -> int
...
Full name: System.String
--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
Full name: Chessie.ErrorHandling.Trial.warn
Full name: Chessie.ErrorHandling.Trial.pass
Full name: Pass-warn-fail.checkFirstName
Full name: Pass-warn-fail.checkLastName
Full name: Pass-warn-fail.checkAge
DateTime.Subtract(value: DateTime) : TimeSpan
type TimeSpan =
struct
new : ticks:int64 -> TimeSpan + 3 overloads
member Add : ts:TimeSpan -> TimeSpan
member CompareTo : value:obj -> int + 1 overload
member Days : int
member Duration : unit -> TimeSpan
member Equals : value:obj -> bool + 1 overload
member GetHashCode : unit -> int
member Hours : int
member Milliseconds : int
member Minutes : int
...
end
Full name: System.TimeSpan
--------------------
TimeSpan()
TimeSpan(ticks: int64) : unit
TimeSpan(hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : unit
Full name: Pass-warn-fail.checkApplicant
Full name: Chessie.ErrorHandling.Trial.bind
Full name: Pass-warn-fail.processRequest
Full name: Chessie.ErrorHandling.Trial.( |Pass|Warn|Fail| )
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Full name: Chessie.ErrorHandling.Trial.( |Pass|Warn|Fail| )
Full name: Pass-warn-fail.disallowPink
Full name: Chessie.ErrorHandling.Trial.fail
Full name: Pass-warn-fail.recheckApplicant
Full name: Pass-warn-fail.reportMessages
Full name: Chessie.ErrorHandling.Trial.( |Pass|Warn|Fail| )
Full name: Pass-warn-fail.warnOnNoColor
Full name: Pass-warn-fail.( checkApplicant (again) )
Full name: Pass-warn-fail.( processRequest (again) )
Full name: Chessie.ErrorHandling.Trial.failOnWarnings