3 ms·
C# is strongly-typed, not stringly-typed. The point of the union is to list possible outcomes as defined through their respective types. The idiomatic way to d
by jzebedee 5mo ago
C# is strongly-typed, not stringly-typed. The point of the union is to list possible outcomes as defined through their respective types.
The idiomatic way to do this would be to parse, don't validate [1] each string into a relevant type with a record or record struct. If you just wanted to return two results of the same type, you'd wrap them in a named tuple or a record that represented the actual meaning.
[1] https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...
- nesarkvechnep 5mo agoI guess C# is more strongly-typed than Haskell then... /s
- goto11 5mo agoYou cant have a `type Foo = String | Strimg` in Haskell either.
- bertylicious 5mo agoBut you can have an `Either String String` which is what GP was talking about.
- bertylicious 5mo agoMy mistake. I see my oversight now. `Either String String` is not equivalent to `String | String`, but to `Left String | Right String`. The same must be done for the C# version.
- goto11 5mo agoYes, you must have individual constructors for the left and right cases in order to distinguish them. In C# you would use two distinct record types for this. Haskell’s syntax is more concise though, since you define the constructors inline in the declaration of the sum type.
- troad 5mo agoString literal typing appears to be a common feature of type systems bolted onto dynamic languages: # Python MyStringBool = Literal("Yes") | Literal("No") // TypeScript type MyStringBool = "Yes" | "No" I assume it exists to compensate for the previous lack of typing, and consequent likelihood of ersatz typing via strings. It would seem pretty unnecessary in Haskell, where you can just define whatever types you want without involving strings at all: data MyBool = Yes | No Of course you'd need a trivial parser, though this is probably a good idea for any string type: parseMyBool :: String -> MyBool parseMyBool "Yes" = Yes parseMyBool "No" = No parseMyBool _ = error "..." Interestingly, dynamic languages which make use of symbols (Ruby, Elixir, Common Lisp) probably fall closer to Haskell than Python or TS. Elixir example: @type my_bool() :: :yes | :no @spec parse_my_bool(String.t()) :: my_bool() def parse_my_bool("Yes"), do: :yes def parse_my_bool("No"), do: :no def parse_my_bool(_), do: throw("...") Where :yes and :no are memory-efficient symbols, not strings.
- nesarkvechnep 5mo agoThank you for the lecture but I didn’t mean that. I meant `Either String String` is possible in Haskell and not in C# because… C# is strongly-typed.
- deleted 5mo ago[deleted]
- troad 5mo agoYou're welcome! Knowing is half the battle. That Haskell snippet is just syntax sugar for Left(string) | Right(string), which is trivial in any language with unions. Not clear why it would be an improvement over just naming the alternatives something meaningful, but if you're wedded to Left and Right, go for it.
- jaen 5mo agoString literals are structural types which are way more expressive than regular (Haskell) ADTs, which are nominal types. In TS in particular, in combination with other features (mapped types), they are equivalent to row polymorphism + whatever Haskell/GHC features enable type families to specialize on constant literal arguments (or you can use atomic types, but that's not structural / open-world)... so pretty advanced. This is valid TS/Python: type ABC = "A" |"B" | "C" type AB = "A" | "B" const x: AB = "A"; const y: ABC = x; The equivalent Haskell requires using several extensions.