>Creating an Optional[Int] from an Int is a conversion, not a cast.

Ok man, take a look at this: https://en.wikipedia.org/wiki/Type_conversion

There is no garbage redefining of a well known word to fit your convenient argument. We are using English and well known terms. This is not obvious to anyone.

Let me illustrate what happened. YOu used a well known term INCORRECTLY, then redefined later claiming that your redefinition was obvious. That is a comedy excuse. No.

You were using a term incorrectly. You man handled the term and you are wrong in that regard.

> eventually you need to provide a default value for the case of no value.

So? It's still type safe. My point is you can't get rid of this problem at all, not even with NonZero int. But via an optional type you guarantee that it's handled. The Rest of your composition needs to live in the Context of that optional. This problem isn't solved by moving it to a post condition.

>Your example doesn't make sense, what would you expect (lookup Map.empty Red) to return?

Ok this I admit I'm wrong. I wasn't thinking detailed enough in that respect so my example was wrong . But this doesn't prove your case at all. There is nothing wrong with using a Maybe monad here. There is zero reason why you need to throw an exception.

>No, this is not necessarily the only way to create instances of NonZero. You could have a PosNat subtype with members one: PosNat and succ: PosNat -> PosNat. You could have a non-empty list type with a length member.

This level of pedantism is too extreme. Nobody uses that type of arithmetic. But if you want to go there fine. You now have a hole in subtraction as 3 - 3 would be a singularity. Your program can no longer use subtraction or addition.

Division and all other mathematical operations have incompatible types. Type casting is 100% necessary to use all operations. The only way I see your Peanno NonZero safetly working is to restrict division to be the exact First set of operations. Then a safe cast can be done without an optional from NonZero to Int for subsequent operations. This is the expansive type casting that is safe and what you're referring to earlier. Either way such an ordering restriction is highly unreasonable but it does offer total safety at the type level.

>They don't return Optional[Int] either so I don't see how this is relevant. There's no reason the input has to come from some application of a different operator, it could come from configuration, user input, a property from some other type etc. The question is whether and how to model the constraints in the type. The constraint exists in the argument so it makes sense to constrain the input type, not widen the output.

If it comes from user input are you saying there's a terminal where the user can never input a zero? If it comes from IO anything goes, you have to be prepared for Anything. Usually the input is String and String -> Int has a shitload of holes.

>Yes, if all you want to do is avoid establishing the property you care about and silently propagate some information-free 'failure' value to the top level, then you can do it either way. But the entire point of encoding properties in the types is to force you to establish them. These statements highlight the difference:

>1. I've established the divisor is non-zero, called myDiv, received an Int and continue

Number 1 cannot be established without creating a singularity or creating strange restrictions as I explained above. If all your program ever does is do division without accepting terms from IO then fine, you win, but let's be real. This is not a realistic expectation and that is my point.