I'm having trouble understanding what exactly a comparable is in Elm. Elm seems as confused as I am.
On the REPL:
> f1 = (<)
<function> : comparable -> comparable -> Bool
So f1 accepts comparables.
> "a"
"a" : String
> f1 "a" "b"
True : Bool
So it seems String is comparable.
> f2 = (<) 1
<function> : comparable -> Bool
So f2 accepts a comparable.
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
comparable
String
So String is and is not comparable?
Why is the type of f2 not number -> Bool? What other comparables can f2 accept?
Normally when you see a type variable in a type in Elm, this variable is unconstrained. When you then supply something of a specific type, the variable gets replaced by that specific type:
-- says you have a function:
foo : a -> a -> a -> Int
-- then once you give an value with an actual type to foo, all occurences of `a` are replaced by that type:
value : Float
foo value : Float -> Float -> Int
comparable is a type variable with a built-in special meaning. That meaning is that it will only match against "comparable" types, like Int, String and a few others. But otherwise it should behave the same. So I think there is a little bug in the type system, given that you get:
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
comparable
String
If the bug weren't there, you would get:
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
Int
String
EDIT: I opened an issue for this bug
Compare any two comparable values. Comparable values include String, Char, Int, Float, Time, or a list or tuple containing comparable values. These are also the only values that work as Dict keys or Set members.
taken from the elm docs here.
In older Elm versions:
Comparable types includes numbers, characters, strings,~~
lists of comparable things, and tuples of comparable things. Note that
tuples with 7 or more elements are not comparable; why are your tuples
so big?
This means that:
[(1,"string"), (2, "another string")] : List (Int, String) -- is comparable
But having
(1, "string", True)` : (Int, String, Bool) -- or...
[(1,True), (2, False)] : List (Int, Bool ) -- are ***not comparable yet***.
This issue is discussed here
Note: Usually people encounter problems with the comparable type when they try to use a union type as a Key in a Dict.
Tags and Constructors of union types are not comparable. So the following doesn't even compile.
type SomeUnion = One | Two | Three
Dict.fromList [ (One, "one related"), (Two, "two related") ] : Dict SomeUnion String
Usually when you try to do this, there is a better approach to your data structure. But until this gets decided - an AllDict can be used.
I think this question can be related to this one. Int and String are both comparable in the sense that strings can be compared to strings and ints can be compared to ints. A function that can take any two comparables would have a signature comparable -> comparable -> ... but within any one evaluation of the function both of the comparables must be of the same type.
I believe the reason f2 is confusing above is that 1 is a number instead of a concrete type (which seems to stop the compiler from recognizing that the comparable must be of a certain type, probably should be fixed). If you were to do:
i = 4 // 2
f1 = (<) i -- type Int -> Bool
f2 = (<) "a" -- type String -> Bool
you would see it actually does collapse comparable to the correct type when it can.
Related
I want to declare ahead of time the value type for a map type.
The functor Map.Make returns a Map.S with two type definitions:
type key
type !+'a t
Type 'a appears to be the type of values in the map. For example, this is the function for adding a key (of type key and value of type 'a:
val add: key -> 'a -> 'a t -> 'a t
One can write the key type like this:
module type M = Map.S with type key = string
But I couldn't figure out how to specify the value type. This isn't valid syntax:
module type M = Map.S with type key = string and 'a = int
One way to look at this is that you're trying to impose monomorphism in the wrong place. The essence of Map.S is that it's polymorphic in the element type.
You can easily define a type for maps from string keys to int values:
# module M = Map.Make(String);;
. . .
# type string_int_mod = int M.t;;
type string_int_mod = int M.t
# let f (m: string_int_mod) s i = M.add s i m;;
val f : string_int_mod -> M.key -> int -> int M.t = <fun>
In many cases, the polymorphism inferred by OCaml is clearer than specifically ascribed types. At least in my opinion. The types inferred by OCaml tell you what the code is really doing and where it has degrees of freedom.
In Kotlin, one can create a range of two numbers by writing a..b, but a < b is necessary for this to not be empty.
Is there a short way for creating the range "between" two arbitrary numbers?
The logic for this would be: min(a,b)..max(a,b)
There's no short way built into the standard library, I'm afraid. But you can easily add your own. Your question gives one way:
fun rangeBetween(a: Int, b: Int) = min(a, b) .. max(a, b)
And here's another:
fun rangeBetween(a: Int, b: Int) = if (a > b) a downTo b else a .. b
(They both behave the same for in checks, but differ in the iteration order: the first one always counts up from the lower to the higher, while the latter will count up or down from the first number to the second.)
Unfortunately those can't be made generic, as both the min()/max() methods and the type of range are different for Ints, Longs, Bytes, Shorts, etc. But you could add overloads for other types if needed.
(I don't know why Kotlin is so fussy about distinguishing ascending and descending ranges. You'd think that this was a fairly common case, and that it would be a simplification to allow ranges to count up or down as needed.)
I was writing a function with user-defined types in OCaml when I encountered an error message that I don't understand.
I'm currently using the OCaml interactive toplevel and also Visual Studio Code to write my code. The strange thing is that when I run the code in Visual Studio Code, it compiles fine but encounters the error in the interactive toplevel.
The OCaml code that I am referring to is as follows:
type loc = int;;
type id = string;;
type value =
| Num of int
| Bool of bool
| Unit
| Record of (id -> loc)
;;
type memory = (loc * value) list;;
exception NotInMemory;;
let rec memory_lookup : (memory * loc) -> value
= fun (mem, l) ->
match mem with
| [] -> raise NotInMemory
| hd :: tl -> (match hd with
| (x, a) -> if x = l then a else (memory_lookup (tl, l))
)
;;
The code that I wrote is basically my rudimentary attempt at implementing/emulating looking up memory and returning corresponding values.
Here's an example input:
memory1 = [ (1, Num 1) ; (2, Bool true) ; (3, Unit) ];;
Here's the expected output:
memory_lookup (memory1, 2);;
- : value = Bool true
However, here's the actual output:
Characters: 179-180:
| (x, a) -> if x = l then "a" else (memory_lookup (tl, l)))
Error: This expression has type value/1076
but an expression was expected of type value/1104
(Just for clarification: the error is regarding character a)
Does anybody know what type value/1076 and type value/1104 mean? Also, if there is anything wrong with the code that I wrote, would anybody be kind enough to point it out?
Thank you.
This kind of error happens in the toplevel when a type is defined multiple times, and some values of the old type are left in scope. A simple example is
type t = A
let x = A;;
type t = A
let y = A;;
x = y;;
Error: This expression has type t/1012 but an expression was expected of type
t/1009
The numerical part after the type name in value/1076 is a binding time for the type value. This binding time is used as a last resort to differentiate between two different types that happens to have the same name. Thus
Error: This expression has type value/1076
but an expression was expected of type value/1104
means that the value memory1 was defined with a type value defined at time 1076, whereas the function memory_lookup expected values of the type value defined at a later date (aka at time 1104). The binding times are a bit arbitrary , so they may be replaced by simply value/1 and value/2 in OCaml 4.08 .
Is there a way to tell Idris to interpret decimal strings such as 2, 10, etc as Nat? The default behavior in the repl is to interpret them as Integer. In Coq, for example, it's possible to specify an interpretation scope with % to disambiguate notations, so I guess I'm hoping that something like 10%Nat exists. Is there something like that in Idris?
The standard prelude contains
the : (a : Type) -> (value: a) -> a
the _ = id
which can be used to give explicit types:
the Integer 10
the Nat 6
the (Vect 3 Int) [1,2,3]
There's also with [namespace] [expr], which privileges namespace inside expr. This seems closer to %, but the seems more often used.
with Vect [['a', 'b']] -- Vect 1 (Vect 2 Char)
with List [['a', 'b']] -- List (List Char)
You can make a syntax extension for the:
syntax [expr] "%" [type] = the type expr
5%Nat
10%Int
But not for with.
I'm reading http://elm-lang.org/guide/model-the-problem and want to better understand Tagged Unions in Elm. Specifically I came across this example:
type Scale = Normal | Logarithmic
type Widget
= ScatterPlot (List (Int, Int))
| LogData (List String)
| TimePlot Scale (List (Time, Int))
The way I think it's interpreted is as follows:
Scale is a type with 2 possible values: Normal or Logarithmic
Widget is a type with 3 possible values: ScatterPlot, LogData, or TimePlot
However, how do I interpret the (List (Int, Int)) part in ScatterPlot? Similarly, how do I interpret the Scale (List (Time, Int)) part in TimePlot?
List is a built-in type, taking one parameter (another type) and meaning "a list containing values of this type as its elements". So List (Int, Int) is a list of (Int, Int). So what's (Int, Int)?
In general any (a, b) is a tuple with members of type a and type b. A tuple is a bit like a record without field names, so you can only distinguish elements by their position - however unlike a list the elements can be of different types. So (Int, Int) is a tuple containing two Ints, where Int is just an integer.
Thus, List (Int, Int) is a list of tuples of two integers.
With TimePlot you've actually got two different type parameters - Scale and List (Time, Int). The latter should now make sense given the explanation of List (Int, Int) - just the tuple has Time as its first type instead of Int.
So TimePlot takes two types as parameters, and it becomes a TimePlot Scale (List (Time, Int)).
In Elm and related languages, type notation (and function application) are defined such that any expression a b c d means a with parameters b, c, and d. If c d is meant to be one parameter it is put in parentheses.
As Andreas says, think of the union 'tags' as functions - they really are, in fact they're called "type constructors". TimePlot is a function taking a Scale and a List (Time, Int) and returning a Widget. Normal is a function with no parameters which returns a Scale, and so on.
Just think about them as function signatures. So Scatterplot must be created like this
ScatterPlot [(1,1), (2,2)]
and when you pattern match this in a case statement
case widget of
ScatterPlot l -> l -- l is from type (List (Int, Int))
LogData l -> l -- l is from type (List String)
TimePlot l -> l -- l is from type Scale (List (Time, Int))