This question already has answers here:
What do Clojure symbols do when used as functions?
(1 answer)
Explain Clojure Symbols
(3 answers)
Closed 8 years ago.
I refer you to this short code:
('a 1)
;==> nil
('a 1 2)
;=>2
why can the symbol a be used as a function in this context?
It allows you to look up a map with the symbol as a key, in a nice syntax.
Below are equivalent:
('a my-hash-map)
(get my-hash-map 'a) ; returns value associated with 'a or nil if not present
For further convenience, you can also supply default value as optional second argument:
('a my-hash-map 42) ; returns 42 if my-hash-map does't have the key 'a
As to you example, ('a 1) returns nil because (get 1 'a) returns nil, and ('a 1 2) returned supplied default value, 2.
Related
I was trying to unwrap the result of List.max_elt of a non-empty list, which should always exist, so I thought Option.value_exn would be the correct tool. But it fails with a strange error:
# List.range 0 10 |> List.max_elt ~cmp:compare;;
- : int option = Some 9
# Option.value_exn (Some 9);;
- : int = 9
# List.range 0 10 |> List.max_elt ~cmp:compare |> Option.value_exn;;
Error: This expression has type
?here:Lexing.position ->
?error:Base.Error.t -> ?message:string -> 'a Base.option -> 'a
but an expression was expected of type int option -> 'b
Can anybody explain this error to me?
I'm using OCaml 4.05.0 and the latest Core library.
The problem here is that something (I'm guessing Option.value_exn) takes optional arguments. When you write it as Option.value_exn x OCaml knows that the optional arguments aren't being used, but when you write it as x |> Option.value_exn it doesn't.
I'm just starting out with F*, by which I mean I've written a few lines along with the tutorial. So far it's really interesting and I'd like to keep learning.
The first thing I tried to do on my own was to write a type that represents a non-empty list. This was my attempt:
type nonEmptyList 'a = l : (list 'a) { l <> [] }
But I get the error
Failed to verify implicit argument: Subtyping check failed; expected
type (a#6468:Type{(hasEq a#0)}); got type Type
I know I'm on the right track though because, if I constrain my list type to containing strings, this does work:
type nonEmptyList = l : (list string) { l <> [] }
I'm assuming this means that l <> [] in the original example isn't valid because I haven't specified that 'a should support equality. The problem is that I cannot for the life of me figure out how to do that. I guess is has something to do with a higher kind called hasEq, but trying things such as:
type nonEmptyList 'a = l : (list 'a) { hasEq 'a /\ l <> [] }
hasn't gotten me anywhere. The tutorial doesn't cover hasEq and I can't find anything helpful in the examples in the GitHub repo so now I'm stuck.
You correctly identified the problem here. The type 'a that you used in the definition of nonEmptyList is left unspecified and therefore could not support equality. Your intuition is correct, you need to tell F* that 'a is a type that has equality, by adding a refinement on it:
To do that, you can write the following:
type nonEmptyList (a:Type{hasEq a}) = l : (list a) { l <> [] }
Note that the binder I used for the type is a and not 'a. It would cause a syntax error, it makes more sense because it isn't "any" type anymore.
Also, note that you can be even more precise and specify the universe of the type a as Type0 if needbe.
Your analysis is indeed correct, and the accepted answer gives the right solution in general.
For your concrete example, though, you don't need decidable equality on list elements: you can just use (list 'a){ ~ (List.isEmpty l) }.
For reference, here's the definition of isEmpty:
(** [isEmpty l] returns [true] if and only if [l] is empty *)
val isEmpty: list 'a -> Tot bool
let isEmpty l = match l with
| [] -> true
| _ -> false
I have a question about mapping lists in ML the problem seems to repeat itself, I have the current datatypes defined :
datatype 'a seq = Nil | Cons of 'a * (unit -> 'a seq);
datatype 'a generic_list = List of 'a list
|Seq of 'a seq;
i'm now trying to write the following function that's supposed to recieve a "'a generic_list" and return a "int generic_list:
val rec generic_map = fn (f,List(lst)) => if lst=nil then List([])
else List(f(List.hd(lst))::generic_map(f,List( List.drop(lst,1))));
That code doesn't compile with the error of : right-hand-side of clause doesn't agree with function result type [tycon mismatch] expression:
'Z generic_list
result type: 'Z list
in declaration:
generic_map =
(fn (f,List lst) =>
if lst = nil
then List nil
else List
(f (List.hd lst) ::
generic_map (f,List (List.drop (lst,1)))))
I would like to know whats the problem here and how I can fix it so it will compile, I cant find the mistake
In the 'else' part, you do something :: generic_map (...), which implies that generic_map would have to return a list instead of a generic_list.
Also, I don't see where you handle the seq case at all.
As a general note, I strongly suggest using pattern matching instead of if, List.hd and friends. In particular a comparison like lst = nil is always wrong, since it restricts the list to elements with equality type -- use pattern matching, or at least the List.null predicate.
Write any Ocaml function whose type is ('a -> 'b) list -> 'a -> 'b list
('a -> 'b) list is the part that confuses me the most. I'm new to OCaml and having a hard time understanding how to write a function to get a specific datatype type.
# let int x = x+1;;
# let fcn = [int; int];;
So I'm passing a function a function and a variable. I'm going to take that variable an add it to each element of the list and return the list?
('a -> 'b) means a function which goes from type 'a to type 'b. Basically you need to make a function which takes a list of functions that take 'a and return 'b, plus a specific 'a value, and which returns a list of 'b values (probably by applying each function of the list of functions to the specific 'a value).
As this is homework, I will not provide you with a complete solution. But, as a hint, I would suggest that you take a look at this implementation of the familiar map function:
let rec map f = function
| [] -> []
| x :: xs -> f x :: map f xs
It has type ('a -> 'b) -> 'a list -> 'b list which means that it takes as its first argument a function that takes values of some type 'a to values of some type 'b, as its second argument a list of elements of type 'a, and that it produces a list of elements of type 'b. It proceeds by pattern matching on the argument list and, recursively applying the function (f) to every element x of the list.
Now have a look at the type of the function that you have to write? What does it tell you about the required behaviour of that function? Keeping the implementation of the map function in mind, how would you write your function?
('a -> 'b) list -> 'a -> 'b list
This means that your function has two parameters
A list of ('a -> 'b) which represents a function taking an element of type 'a as a parameter and returning an element of type 'b. As you can see, these types are abstract, so they could be of any types for instance (int -> int) or (int -> float) etc...
An elements of types 'a. Notice that this type must be the same as the parameter of your function.
So you'll build the resulting list with the element you give as a parameter.
Here is a little example:
let action l a =
let rec todo l res =
match l with
| [] -> res
| h :: t -> todo t res#[h a] in
todo l []
so here, any function of type int -> int will be accepted. The same thing goes for any other type as long as you don't mix them with other types.
let rec func f a = match f with (* ( 'a->'b ) list -> 'a -> 'b list *)
|[]->[]
|x::lr -> x a :: func lr a;;
that may help ! it works fine
1 - So as we know , ocaml create the type of our function line by line
2 - in this function we have two arguments f and a
3 - ( 'a->'b ) list : for f
4 - 'a : for a ! how ocaml did that ? listen !
5 - when we matched f with [ ] 'blank list' ocaml release that is a list (****)list but doesn't know what contains yet in the last line of the code he will do ok ? nice !
- here we are in the last line of the code and we have only f of type list -
6 - x :: lr means we sort the first element of the element that is matched before : f and we add a here ocaml gives a type for a and for the list elements which is matched : f as first elements ocaml gives them types from 'a to 'z so here we have ('a->'b) list for f and 'a for a
-here we have f of type : ('a->'b) list , and a of type : 'a
7 - the result of this function 'b list so it's up to you to answer in comment ! :D thank you
Why does this series of clojure commands return false and not true? What is the difference between the result of statement 1 "C" and 2 "(quote C)"?
; SLIME 2009-03-04
user> ('A 'B 'C)
C
user> (last '('A 'B 'C))
(quote C)
user> (= ('A 'B 'C) (last '('A 'B 'C)))
false
This question is somewhat similar to How does clojure's syntax-quote work?
In Clojure (and other Lisps) the ' is a shortcut for the form (quote ...). So when Clojure sees this:
('A 'B 'C)
which is "translated" by the reader into:
((quote A) (quote B) (quote C))
Each of those quote forms evaluates to a symbol, so (quote A) evaluates to the symbol named A. In Clojure, symbols are functions and can be applied, so ((quote A) (quote B) (quote C)) is actually a function call. From the docs:
"Symbols, just like Keywords, implement IFn for invoke() of one argument (a map) with an optional second argument (a default value). For example ('mysym my-hash-map :none) means the same as (get my-hash-map 'mysym :none)."
So what happens is that C is the default value and that's why it's returned.
Meanwhile, this
'('A 'B 'C)
is translated by the reader into
(quote ((quote A) (quote B) (quote C)))
Which is actually a list of three elements, each of which is a list of two elements, the symbol quote and another symbol (in this case A, B, C).
So, (last '('A 'B 'C)) is actually (quote C). That's the difference between those two results, C is the symbol with the name C while (quote C) is a list of two elements.
You can confirm this:
user=> (class ('A 'B 'C))
clojure.lang.Symbol
user=> (class (last '('A 'B 'C)))
clojure.lang.PersistentList
user=>
Hope that's clear!
('x 'y) is very unusual, for just this reason. Usually you want '(x y), which is a list of the literal symbols x and y. If you quote TWICE with '('x 'y), you get a list with (quote x) instead: the literal symbol quote, followed by the literal symbol x.