80 lines
1.7 KiB
Nix
80 lines
1.7 KiB
Nix
{this, ...}: let
|
|
inherit
|
|
(builtins)
|
|
attrNames
|
|
concatStringsSep
|
|
isAttrs
|
|
typeOf
|
|
;
|
|
|
|
inherit
|
|
(this.std)
|
|
id
|
|
;
|
|
in rec {
|
|
# NOTE: Maybe intentionally doesn't use the NixTypes.
|
|
# NOTE: Maybe is used to aid in parsing and bootstrapping.
|
|
# NOTE: It is intentionally left simple for speed gains.
|
|
Maybe = some: value: {
|
|
_some = some;
|
|
_value = value;
|
|
};
|
|
Some = Maybe true;
|
|
None = Maybe false null;
|
|
|
|
# Type Checking
|
|
isMaybe = T: isAttrs T && attrNames T == ["_some" "_value"];
|
|
enfIsMaybe = T: msg: let
|
|
throw' = got: throw "${msg}: expected naive type Maybe but got ${got}";
|
|
attrs =
|
|
attrNames T
|
|
|> map (name: "\"${name}\"")
|
|
|> concatStringsSep ", ";
|
|
in
|
|
if isAttrs T
|
|
then isMaybe T || throw' "attribute set with structure [${attrs}]"
|
|
else throw' "value \"${toString T}\" of primitive type \"${typeOf T}\"";
|
|
|
|
isSome = T:
|
|
assert enfIsMaybe T "isSome";
|
|
T._some;
|
|
|
|
isNone = T:
|
|
assert enfIsMaybe T "isNone";
|
|
! T._some;
|
|
|
|
# Monadic Bind Operation
|
|
bindMaybe = f: T:
|
|
if isSome T
|
|
then Some (f T._value)
|
|
else T;
|
|
|
|
# Unwrap Operations
|
|
# Lift a value out of the monadic context.
|
|
unwrapMaybe = T:
|
|
assert enfIsMaybe T "unwrapMaybe"; T._value;
|
|
|
|
# Map Operations
|
|
# Lift a value out of the monadic context and expect a new monadic.
|
|
mapMaybe = f: g: T: let
|
|
value =
|
|
if isSome T
|
|
then f T._value
|
|
else g T._value;
|
|
in
|
|
assert enfIsMaybe value "mapMaybe"; value;
|
|
|
|
mapSome = f: mapMaybe f id;
|
|
mapNone = mapMaybe id;
|
|
|
|
# Utility Functions
|
|
boolToMaybe = x:
|
|
if x
|
|
then Some true
|
|
else None;
|
|
|
|
nullableToMaybe = x:
|
|
if x == null
|
|
then None
|
|
else Some x;
|
|
}
|