agentm / project-m36

Project: M36 Relational Algebra Engine
The Unlicense
894 stars 48 forks source link

Unable to construct a generic type where the type argument can't be determined #266

Closed johnwright closed 4 years ago

johnwright commented 4 years ago

If I define a basic generic type:

data Option a = Some a | None

And the following relation:

person :: {name Text, age Option Int}

Then I'm able to assign a Some value since the type argument is obvious from the context:

person := relation{tuple{name "Fred", age Some 10}}

But not a None value:

person := relation{tuple{name "Fred", age None}}
ERR: TypeConstructorTypeVarMissing "t"

Is there a way to add a type ascription, e.g. age (None :: Option Integer)?

I realise this pattern may look like a "back door" to adding back NULLs, but I'm curious to whether this can work more generally. Thanks!

agentm commented 4 years ago

Yes, please use the following syntax which is vaguely equivalent to a type signature:

TutorialD (master/main): person := relation{name Text, age Option Int}{tuple{name "Fred", age None}}
TutorialD (master/main): :showexpr person
┌────────────────────┬──────────┐
│age::Option (a::Int)│name::Text│
├────────────────────┼──────────┤
│None                │"Fred"    │
└────────────────────┴──────────┘

Note that Option a is not equivalent to NULL as in SQL because None::Option Int is equal to None::Option Int.

Check out the TutorialD Cheatsheet for more examples and the short essay "On Null" for more details on how NULLs are problematic.

agentm commented 4 years ago

Note that, in the case of Project:M36, you don't necessarily need to overload meaning to type constructors. For example, the case above might be clearer as:

data Age = SpecificAge Int | UserRefusedToSpecifyAge | UnknownForOtherReasonsAge
johnwright commented 4 years ago

Thanks, that's extremely helpful!