diff --git a/nt/primitives/bootstrap/default.nix b/nt/primitives/bootstrap/default.nix index e78a733..276aa45 100644 --- a/nt/primitives/bootstrap/default.nix +++ b/nt/primitives/bootstrap/default.nix @@ -34,6 +34,8 @@ let std = ./std/bootstrap.nix; types = ./types/bootstrap.nix; parse = ./parse/bootstrap.nix; + + maybe = ./maybe.nix; trapdoor = ./trapdoor.nix; } ]; diff --git a/nt/primitives/bootstrap/maybe.nix b/nt/primitives/bootstrap/maybe.nix new file mode 100644 index 0000000..0833256 --- /dev/null +++ b/nt/primitives/bootstrap/maybe.nix @@ -0,0 +1,81 @@ +{...}: let + inherit + (builtins) + attrNames + concatStringsSep + isAttrs + typeOf + ; +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; + + # Pattern Matching (unsafe and safe variants) + isMaybe = 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 throw' "attribute set with structure [${attrs}]" + else throw' "value \"${toString T}\" of primitive type \"${typeOf T}\""; + + # isSome = T: isMaybe T && T._some; + # isNone = T: isMaybe T && ! T._some; + + isSome = T: + assert enfIsMaybe T "isMaybeSome"; + T._some; + + isNone = T: + assert enfIsMaybe T "isMaybeNone"; + ! T._some; + + # TODO: ensure you check isNone if isSome fails (otherwise it could be another type!) + # Unwrap (Monadic Return Operation) + # unwrapMaybe = f: g: T: + # if isSome T + # then f T._value_ + # else g T._value_; + # unwrapSome = unwrapMaybe (v: v); + # unwrapNone = f: unwrapMaybe f (v: v); + + # Map (Monadic Bind Operation) + mapMaybe = f: T: + if isSome T + then Some (f T._value) + else T; + + # Conditionals + # someOr = f: T: + # if isSome T + # then T + # else f T; + + # noneOr = f: T: + # if isNone T + # then T + # else f T; + + boolToMaybe = x: + if x + then Some true + else None; + + nullableToMaybe = x: + if x == null + then None + else Some x; + + maybeTobool = isSome; +} diff --git a/nt/primitives/bootstrap/trapdoor.nix b/nt/primitives/bootstrap/trapdoor.nix index d85b613..ebc30f4 100644 --- a/nt/primitives/bootstrap/trapdoor.nix +++ b/nt/primitives/bootstrap/trapdoor.nix @@ -12,7 +12,7 @@ ; inherit - (this.types) + (this.maybe) Some None ; diff --git a/nt/primitives/bootstrap/types/bootstrap.nix b/nt/primitives/bootstrap/types/bootstrap.nix index 0b06740..8568a44 100644 --- a/nt/primitives/bootstrap/types/bootstrap.nix +++ b/nt/primitives/bootstrap/types/bootstrap.nix @@ -2,6 +2,5 @@ # WARNING: this file is strictly for bootstrapping nt {bootstrap, ...} @ inputs: bootstrap inputs [ - ./maybe.nix ./wrap.nix ] diff --git a/nt/primitives/bootstrap/types/maybe.nix b/nt/primitives/bootstrap/types/maybe.nix deleted file mode 100644 index 8ab36b1..0000000 --- a/nt/primitives/bootstrap/types/maybe.nix +++ /dev/null @@ -1,80 +0,0 @@ -{this, ...}: let - inherit - (this) - ntTrapdoorKey - ntDynamicTrapdoorKey - ; - - inherit - (this.std) - enfImpls - ; - - inherit - (this.trapdoor) - mkTrapdoorFn - mkTrapdoorSet - openTrapdoor - ; -in { - # NOTE: Maybe is used to simplify parsing Type/Class declarations - # NOTE: and therefore must be implemented manually - Maybe = let - meta = instance: { - sig = "nt::&Maybe"; - derive = []; - ops = {}; - req = {"nt::&Maybe" = ["unwrap"];}; - }; - in - mkTrapdoorFn { - default = { - unwrap = T: - assert enfImpls "nt::&Maybe" T "nt::&Maybe.unwrap"; - (T |> openTrapdoor ntTrapdoorKey).ops."nt::&Maybe".unwrap; - }; - unlock.${ntTrapdoorKey} = meta false; - }; - - Some = let - meta = instance: { - inherit instance; - sig = "nt::Some"; - derive = ["nt::&Maybe"]; - ops = { - "nt::&Maybe".unwrap = f: self: f self.${ntDynamicTrapdoorKey}.value; - }; - req = {}; - }; - in - mkTrapdoorFn { - default = value: - mkTrapdoorSet { - unlock = { - ${ntTrapdoorKey} = meta true; - ${ntDynamicTrapdoorKey} = { - inherit value; - }; - }; - }; - unlock.${ntTrapdoorKey} = meta false; - }; - - None = let - meta = instance: { - inherit instance; - sig = "nt::None"; - derive = ["nt::&Maybe"]; - ops = { - "nt::&Maybe".map = f: self: self; - }; - req = {}; - }; - in - mkTrapdoorFn { - default = mkTrapdoorSet ntTrapdoorKey { - unlock = meta true; - }; - unlock.${ntTrapdoorKey} = meta false; - }; -}