In other words, maybe type checking doesn't go far enough: checking that I'm getting an int is less valuable than checking that I'm getting the right sort of data for the domain.
In other words, maybe type checking doesn't go far enough: checking that I'm getting an int is less valuable than checking that I'm getting the right sort of data for the domain.
type Length = Inches Int
Then any function that accepts a Length, you can only pass in a length. This effectively acts like tagged tuples verified at compile time. You can later extend this type to be: type Length = Inches Int | Meters Int
and any code that reads length would have to handle both cases (also checked at compile that).I have found this to be a great way of ensuring all of your types are correct (and sometimes, a great frustration of wishing I didn't have to wrap/unwrap types so often).
[1] https://fsharpforfunandprofit.com/posts/units-of-measure/
I'm thinking of it in an OO style, where perhaps instead of wrapping/unwrapping you're specifying an analog to object properties.
I'm really not sure if that could be in any way practical at all, but I like the idea.
type Year = Int
type Month = Int
type Day = Int
-- fields have no names, just types
data Date = Date Year Month Day
-- we bind fields to names only when necessary
next (Date y 12 31) = Date (y + 1) 1 1
next (Date y m d)
| d == daysOf m = Date y (m + 1) 1
| otherwise = Date y m (d + 1)
where daysOf = (!!) [0, 31, 28, 31, 30,
31, 30, 31, 31,
30, 31, 30, 31]
Is something like this what you mean?Maybe those who don't know Haskell are doomed to reinvent isolated parts of it.
[0] https://lexi-lambda.github.io/blog/2016/06/12/four-months-wi...
It enforces correct units/dimensions at compile time, so you won’t be able to mix up length with time or area, etc.