Stream: beginners

Topic: string format type


view this post on Zulip Albert (Jun 16 2024 at 16:24):

Is it possible to define a string type that only contain strings of some format? Such as a RFC3339 timestamp

view this post on Zulip Albert (Jun 16 2024 at 16:24):

The same question goes to: is it possible to define range types such as only integers > 10

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:25):

Kinda, but indirectly

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:25):

You would use an opaque type and force the opaque type constructor to enforce the rules

view this post on Zulip Albert (Jun 16 2024 at 16:25):

Can you give me an example?

view this post on Zulip Albert (Jun 16 2024 at 16:26):

This is useful when I deal with cryptographic strings that has to follow certain format

view this post on Zulip Albert (Jun 16 2024 at 16:27):

I only want to validate them once after the IO and use the correct type afterwards

view this post on Zulip Albert (Jun 16 2024 at 16:27):

A niche use case for sure

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:29):

So for the integer you would make an opaque type

AboveTenInt := I64

Then you would only expose a constructor that ensures it's valid

create: I64 -> Result AboveTenInt [NotAboveTen]
create = \i ->
    if i > 10 then
        Ok (@AboveTenInt i)
    else
        Err NotAboveTen

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:29):

Then make sure any functions that modify an above ten int also deal with keeping it above ten or returning an error.

view this post on Zulip Albert (Jun 16 2024 at 16:29):

Is create a special function?

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:30):

Not particularly. It just has to be in the same module where AboveTenInt is defined so it can access the wrapper function @AboveTenInt.

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:31):

So you protect wrapping and unwrapping of opaque types using the module boundary

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:31):

As long as you have correct functions within the module, nothing outside the module can break the opaque type. They will only be able to modify it by calling those special opaque type functions.

view this post on Zulip Albert (Jun 16 2024 at 16:33):

some kind of like public/private functions in a imperative language

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:33):

Essentially

view this post on Zulip Albert (Jun 16 2024 at 16:34):

anything that can produce an AboveTenInt is defined in the module

view this post on Zulip Albert (Jun 16 2024 at 16:34):

What if I just declare a literal as AboveTenInt outside the module?

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:38):

Would have to go through create. Though you could also make a version that panics instead of returns an error. That would be greater for constants, but dangerous otherwise.

Long term we want better support for compile time eval that could fold away and unwrap constants (with compile time asserts that they unwrap safely)

view this post on Zulip Albert (Jun 16 2024 at 16:48):

more like Rust macro or Zig comptime?

view this post on Zulip Albert (Jun 16 2024 at 16:48):

or just a built-in compiler feature?

view this post on Zulip Brendan Hansknecht (Jun 16 2024 at 16:59):

Probably like zig comptime, but less powerful (no metaprogramming via passing around and manipulating types). So really just evaluation of constants and functions that have all inputs know at compile time.


Last updated: Jul 05 2025 at 12:14 UTC