What is the difference between the following F# casting operators? I can't seem to understand why and how they are all different.
(type) X
X :> type
X :?> type
The first isn't a cast in F#, though if you're used to C# it might appear that it works like one. But this is actually invoking a type conversion function (like int), and the parentheses aren't actually required (and are just likely to make everything more confusing).
(int) "4" // the number 4 - this is a conversion, not a cast
int "4" // same thing, but idiomatic
int "NaN" // compiles but throws an exception at runtime
(int) (box 4) // doesn't compile because int doesn't do downcasts, just known conversions
Note that this works for primitive types, because there are predefined conversion functions, but it won't work for arbitrary types:
(bigint) 1 // no such conversion function, so this is a compile-time error
The difference between the other two is that :> performs upcasts (from a type to a supertype, which is always safe) and :?> performs downcasts (from a type to a subtype, which might fail, thus the '?' in the middle).
There are also named upcast and downcast operators which can be used in a similar way:
5 :> obj // upcast int to obj
(upcast 5 : obj) // same
(box 5) :?> int // downcast an obj to int (successfully)
(downcast (box 5) : int) // same
(box "5") :?> int // downcast an obj to int (unsuccessfully)
In some contexts the target type of the upcast or downcast may be successfully inferred, in which case you don't need the type annotations when using the upcast or downcast operators, while you always need to provide a type argument to the :> or :?> operators (though you can supply _ if you expect it to be inferred):
List.map (fun x -> x + 1) (downcast (box [1]))
List.map (fun x -> x + 1) (box [1] :?> _)
Related
I'm just starting to learn OCaml, and I was confused by how the OCaml compiler determines the input type of arguments in certain situations where the argument could be multiple types. I'm assuming I would need to explicitly state the type in these instances? For example:
let sign x =
if x > 0 then 1
else if x < 0 then -1
else 0
let _ = print_int(sign 1.5)
Throws "Error: This expression has type float but an expression was expected of type int"
But don't the comparison operators work with floats as well? Why does the compiler assume that the argument should be an int instead of saying something like the argument type is ambiguous (unless I'm mistaken and the type actually is not ambiguous)?
The built-in comparison operators in OCaml have the following type signature:
'a -> 'a -> bool. Note that while the argument types are generic ('a), they are both the same. So, when you have a comparison like x < 0, the compiler sees that the type of the second argument is int and then infer that the type of x must be int as well. Changing your comparisons to use floats, e.g. x < 0. will make your code type-check, but then it would no longer work for int inputs.
In F#, many infix operators can be made prefix operators:
a + b
(+) 1 a b
However, this doesn’t seem to be allowed for the upcast (or downcast) operators.
x is a UserPrincipal, which inherits from Principal
x :> Principal
(:>) x Principal
Why?
Probably because unlike other operators, the cast operators don't take two expressions as arguments; they take an expression and a type. So (:>) x would have to be "a function that takes a type", which is not a thing that exists in F#.
I'm working on an assignment where I have to write a function to get the length of a list. This is a trivial task, but I've come across something that I don't understand.
My simple code
val len = foldr (fn(_, y) => y + 1) 0
produces this warning
Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
and when I try to run it in the REPL, I get this:
len [1, 2, 3, 4];
stdIn:18.1-18.17 Error: operator and operand don't agree [overload conflict]
operator domain: ?.X1 list operand:
[int ty] list in expression:
len (1 :: 2 :: 3 :: <exp> :: <exp>)
I don't understand why this doesn't work. I do know some functional programming principles, and this should work, since its very simple partial application.
Of course I can make it work without partial application, like this
fun len xs = foldr (fn(_, y) => y + 1) 0 xs
but I would like to understand why the first version doesn't work.
This is an instance of the value restriction rule application:
In short, the value restriction says that generalization can only occur if the right-hand side of an expression is syntactically a value.
Syntactically,
foldr (fn(_, y) => y + 1) 0
is not a value, it's a function application, that's why it hasn't been assigned a polymorphic type. It has been instantiated with a dummy type, which has a very limited use, e.g. this works:
len []
but in most cases len defined as val is useless.
This restriction exists to guarantee type safety in the presence of variable assignment (via references). More details can be found in the linked page.
Let's consider a type t and two variables x,y of type t.
Will the call compare x y be valid for any type t? I couldn't find any counterexample.
The polymorphic compare function works by recursively exploring the structure of values, providing an ad-hoc total ordering on OCaml values, used to define structural equality tested by the polymorphic = operator.
It is, by design, not defined on functions and closures, as observed by #antron. The recursive nature of the definition implies that structural equality is not defined on values containing a function or a closure. This recursive nature also imply that the compare function is not defined on recursive values, as mentioned by a #antron as well.
Structural equality, and therefore the compare function and the comparison operators, is not aware of structure invariants and cannot be used to compare (mildly) advanced data structures such as Sets, Maps, HashTbls and so on. If comparison of these structures is desired, a specialised function has to be written, this is why Set and Map define such a function.
When defining your own structures, a good rule of thumb is to distinguish between
concrete types, which are defined only in terms of primitive types and other concrete types. Concrete types should not be used for structures whose processing expects some invariants, because it is easy to create arbitrary values of this type breaking these invariants. For these types, the polymorphic comparison function and operators are appropriate.
abstract types, whose concrete definition is hidden. For these types, it is best to provide specialised comparison function. The mixture library defines a compare mixin that can be used to derive comparison operators from the implementation of a specialised compare function. Its use is illustrated in the README.
It doesn't work for function types:
# compare (fun x -> x) (fun x -> x);;
Exception: Invalid_argument "equal: functional value".
Likewise, it won't (generally) work for other types whose values can contain functions:
# type t = A | B of (int -> int);;
type t = A | B of (int -> int)
# compare A A;;
- : int = 0
# compare (B (fun x -> x)) A;;
- : int = 1
# compare (B (fun x -> x)) (B (fun x -> x));;
Exception: Invalid_argument "equal: functional value".
It also doesn't (generally) work for recursive values:
# type t = {self : t};;
type t = { self : t; }
# let rec v = {self = v};;
val v : t = {self = <cycle>}
# let rec v' = {self = v'};;
val v' : t = {self = <cycle>}
# compare v v;;
- : int = 0
# compare v v';;
(* Does not terminate. *)
These cases are also listed in the documentation for compare in Pervasives.
Assuming I have an int64 variable (or other integer size) representing a valid unicode code-point, and I want to convert it into a rune in Go, what do I do?
In C I would have used a type cast something like:
c = (char) i; // 7 bit ascii only
But in Go, a type assertion won't work:
c, err = rune.( i)
Suggestions?
You just want rune(i). Casting is done via type(x).
Type assertions are something different. You use a type assertion when you need to go from a less specific type (like interface{}) to a more specific one. Additionally, a cast is checked at compile time, where type assertions happen at runtime.
Here's how you use a type assertion:
var (
x interface{}
y int
z string
)
x = 3
// x is now essentially boxed. Its type is interface{}, but it contains an int.
// This is somewhat analogous to the Object type in other languages
// (though not exactly).
y = x.(int) // succeeds
z = x.(string) // compiles, but fails at runtime
In Go, you want to do a conversion.
Conversions
Conversions are expressions of the form T(x) where T is a type and
x is an expression that can be converted to type T.
Conversion = Type "(" Expression ")" .
A non-constant value x can be converted to type T in any of these
cases:
x is assignable to T.
x's type and T have identical underlying types.
x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
x's type and T are both integer or floating point types.
x's type and T are both complex types.
x is an integer or has type []byte or []rune and T is a string type.
x is a string and T is []byte or []rune.
You want to convert x, of type int, int32, or int64, to T of type rune, an alias for type int32. x's type and T are both integer types.
Therefore, T(x) is allowed and is written rune(x), for your example, c = rune(i).