diff --git a/nt/primitives/util/bootstrap.nix b/nt/primitives/util/bootstrap.nix index 85313cf..9299236 100644 --- a/nt/primitives/util/bootstrap.nix +++ b/nt/primitives/util/bootstrap.nix @@ -6,6 +6,7 @@ let // import ./parse.nix input // import ./trapdoor.nix input // import ./null.nix input + // import ./maybe.nix input // import ./wrap.nix input // import ./enforce.nix input // import ./sig.nix input diff --git a/nt/primitives/util/default.nix b/nt/primitives/util/default.nix index 008e9d7..844594d 100644 --- a/nt/primitives/util/default.nix +++ b/nt/primitives/util/default.nix @@ -4,6 +4,7 @@ mix.newMixture inputs (mixture: { ./enforce.nix ./nt.nix ./null.nix + ./maybe.nix ./parse.nix ./sig.nix ./trapdoor.nix diff --git a/nt/primitives/util/enforce.nix b/nt/primitives/util/enforce.nix index b18e417..5721ac5 100644 --- a/nt/primitives/util/enforce.nix +++ b/nt/primitives/util/enforce.nix @@ -7,9 +7,11 @@ inherit (this) + impls isClassSig isNT isTypeSig + toTypeSig ; in rec { enfIsType = type: value: msg: let @@ -33,4 +35,9 @@ in rec { enfIsNT = T: msg: isNT T || throw "${msg}: expected nt compatible type but got \"${toString T}\" of primitive nix type \"${typeOf T}\""; + + # assert enfImpls "nt::&Maybe" T "nt::&Maybe.unwrap"; + # impls = type: T: assert enfIsNT T "nt.impls"; impls' type T; + enfImpls = type: T: msg: + impls type T || throw "${msg}: given type \"${toTypeSig T}\" does not implement typeclass \"${toTypeSig type}\""; } diff --git a/nt/primitives/util/maybe.nix b/nt/primitives/util/maybe.nix new file mode 100644 index 0000000..ab272a1 --- /dev/null +++ b/nt/primitives/util/maybe.nix @@ -0,0 +1,72 @@ +{this, ...}: let + inherit + (this) + enfImpls + mkTrapdoorFn + mkTrapdoorSet + ntTrapdoorKey + ntDynamicTrapdoorKey + 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; + }; +}