How to let option expressions simplfy in Isabelle? - isabelle

I am trying to understand options in Isabelle (2020), and couldn't understand why some simple expressions of option do not compute or simplify as expected.
For example, I'd expect that
value "some (1::nat)"
should return an "nat option" type, yet, it returns an unspecified type:
"some 1"
:: "'a
More over, from the type signature, I'd expect the the function the return the value "inside" the option, so that "the (some (1::nat))" is just (1::nat).
However,
value "the (some (1::nat))"
returns a seemingly not very useful type:
"the (some 1)"
:: "'a"
, which isn't nat. Then the result isn't very useful, e.g.
value "the (some (1::nat)) + 2"
returns
"the (some 1) + (1 + 1)"
:: "'a"
(I expected the result to be "3::nat")
Is this by design or am I missing something about the, or how options simplify/compute in Isabelle?
( I have no prior knowledge about Isabelle options, and I am just assuming it's similar to Haskell's Maybe. )

A C-click on the shows that the definition is:
datatype 'a option =
None
| Some (the: 'a)
It is Some, not some.
There is a hint to see that some is not defined: the color is not the same as the color from the.

Related

Why are my types not working out? (Use of type 'a pred = 'a -> bool)

I have been stuck on this question for a while. I've been editing and reviewing and changing the types for a while but I can't get the type checker to accept what I am doing, probably because I don't fully understand the error/where I am going wrong on this. I am working with the type:
type 'a pred = 'a -> bool
I believe this means I can use 'a pred as a shortcut to mean 'a -> bool, so an int going to result in a bool in my case, but I don't fully get how to implement it because I can't find many examples on this online which I have checked for.
My latest version is below, but I am getting a few errors from the checker, including Error: operator and operand do not agree. Would someone be able to explain where my error is, and why?
Edit: I now think there is a mismatch between this function and the rest of the code. The rest of the code requires it to be an 'a, polymorphic, while here I am assuming it is an int. However, I'm not sure how to do this function (check if odd) while keeping it a polymorphic type.
fun isOdd (p : int) : bool =
case p
of 1 => true
| 0 => false
| _ => isOdd (p - 2)
I believe this means I can use 'a pred as a shortcut to mean 'a -> bool
That is correct.
In the case of your isOdd predicate, it is an int pred:
> val isOdd = fn : int -> bool
- isOdd : int pred;
> val it = fn : int -> bool
Perhaps your misconception lies in the fact that in spite of expressing : int pred, the result in the REPL is still described as int -> bool? This is because we have only defined a type alias, and those tend reduce to their non-aliased form in SML.
Or perhaps your misconception lies in the 'a reducing to some concrete value? You can operate with 'a pred by not referring to concrete values of 'a. For example, if you want to filter an 'a list for only values that are true for a given 'a pred, then the standard function List.filter will have the type:
- List.filter : 'a pred -> 'a list -> 'a list;
> val 'a it = fn : ('a -> bool) -> 'a list -> 'a list
I'm not sure how to do this function (check if odd) while keeping it a polymorphic type.
I'm not sure, either.
Oddness is a property of integers, not arbitrary types 'a.
You would need to extend the meaning of "odd" to any type first. Then you would need some kind of overloading, since the oddness of every type presumably isn't determined by the same mechanism. I'm pretty sure this is a side-track caused by one or two confusions.

Defining a function which returns functions in Isabelle

I'm trying to do the following simple thing: given a topological space, extract its topology and view it as a poset. For that, I imported Topology.thy and Orders.thy and tried something along these lines
fun undtop :: "'a top ⇒'a partial_order" where
"undtop T = (leq ::"T ⇒ T ⇒ bool" where
"leq x y = (x ⊆ y)")"
where 'a top is the type 'a set set and partial_order is of type 'a=>'a => bool (the theory Orders.thy defines a class class partial_order) . The idea was that some T of type a' top should give the topology and then undtop would pick such a T and associate a partial order leq, viewed as a map T => T => bool. Clearly this is not how it works, so I'd like to ask
1) How would you define a function that picks each T of a certain type and defines a new function with domain T?
2) How to specify that this T of type 'a top is a topology, and not just a random collection of subsets, i.e how do I tell Isabelle that it should obey the axioms of the locale "topology" in Topology.thy?
Thank you for the support, as a beginner I'm still struggling with the syntax and the way Isabelle operates.

How do I view hidden type variables in Isabelle proof goals?

In Isabelle, one can often hit proof goals where the intermediate type of terms is critical to a proof's correctness. For instance, consider the following lemma converting the nat 42 into an 'a word then back again:
theory Test
imports "~~/src/HOL/Word/Word"
begin
lemma "unat (of_nat 42) = 42"
...
Now the truth of this statement depends on the type of of_nat 42: if it is 32 word, then the statement is true, if it is a 2 word, however, the statement is false.
Unfortunately, I can't seem to get Isabelle to display this intermediate type to me.
I have tried the following:
declare [[show_types]]
declare [[show_sorts]]
local_setup {* Config.put show_all_types true *}
all of which just display:
unat (of_nat (42::nat)) = (42::nat)
In a pinch, one can do:
apply (tactic {* (fn t => (tracing (PolyML.makestring (prems_of t)); all_tac t)) *})
do get a raw dump of the term, but I was hoping there was a better way.
Is there a good way of displaying intermediate term types in a proof goal?
In Isabelle/jEdit you can always "control-hover" (i.e., keep the control-button pressed and hover the mouse) over a constant in order to get additional information. For of_nat in
lemma "unat (of_nat 42) = 42"
This results in
constant "Nat.semiring_1_class.of_nat"
:: nat => 'a word
Now you can recursively do the same on 'a of 'a word and will get
:: len
free type variable
which tells you that 'a is of sort len (by control-clicking len, you could directly jump to the definition of this type class, which is also quite handy).
So the answer to your question is: yes, control-hover in Isabelle/jEdit.
To make Isabelle show you the type of unat in this example, you want to declare the following:
declare [[show_types]]
declare [[show_sorts]]
declare [[show_consts]]
The last line prints the type of each constant used in the goal in the output window. This works both in jEdit and ProofGeneral.
There is a problem with this solution: if unat occurs multiple times with different types, it will print all these instances, but it will not tell you which type instance is which occurrence. Apart from the jEdit hover, I don't know of any solution for that, though.
Running the command:
setup {* Config.put_global show_all_types true *}
seems to do the trick.
The goal unat (of_nat 3) = 3 becomes the hideous (but complete):
goal (1 subgoal):
1. (Trueprop::bool => prop)
((op =::nat => nat => bool)
((unat::'a word => nat)
((of_nat::nat => 'a word)
((numeral::num => nat)
((num.Bit1::num => num) (num.One::num)))))
((numeral::num => nat)
((num.Bit1::num => num) (num.One::num))))
as desired.
It is interesting that a declare [[show_all_types]] does not work; the source looks like it should. Perhaps it is a bug in Isabelle2013?

Extending OCaml Maps to formattable Maps

I have made a functor for format-able sets, as follows:
module type POrderedType =
sig
type t
val compare : t -> t -> int
val format : Format.formatter -> t -> unit
end
module type SET =
sig
include Set.S
val format : Format.formatter -> t -> unit
end
module MakeSet (P : POrderedType) : SET with type elt = P.t
Implementation of this is straightforward:
module MakeSet (P : OrderedType) =
struct
include Set.Make(P)
let format ff s =
let rec format' ff = function
| [] -> ()
| [v] -> Format.fprintf ff "%a" format v
| v::tl -> Format.fprintf ff "%a,# %a" format v format' tl in
Format.fprintf ff "#[<4>%a#]" format' (elements s)
end
I wanted to do something similar with maps. POrderedType is fine for keys, but I need a simpler type for values:
module type Printable =
sig
type t
val format : Format.formatter -> t -> unit
end
Then I wanted to do something similar to what I had done for sets, but I run into the following problem. Map.S values have type +'a t. I can't figure out a way to include the Map.S definition while constraining the 'a to be a Printable.t. What I want is something like the following (ignoring the fact that it is illegal):
module MakeMap (Pkey : POrderedType) (Pval : Printable) :
MAP with type key = Pkey.t and type 'a t = 'a t constraint 'a = Pval.t
Is there any way to do what I want without copying the entire signature of Map by hand?
I think the cleanest way to propose a printing function for polymorphic maps is to make the map printing function parametric over the values printing function. You can think of it this way:
functor-defined types are defined at the functor level, so providing functions for them is best done by adding new functor parameters (or enriching existing ones)
parametric types are bound (generalized) at the value level, so providing functions for them is best done by adding new parameters to the value
In OCaml, convenience tend to make people favor parametric polymorphism over functorization when possible. Functorization is sometimes necessary to enforce some type safety (here it's used to make sure that maps over different comparison functions have incompatible types), but otherwise people rather try to have polymorphism. So you're actually in the lucky situation here.
If you really want to have a functor producing monomorphic maps, well, I'm afraid you will have to copy the whole map interface and adapt it in the momonorphic case -- it's not much work.

Does "Value Restriction" practically mean that there is no higher order functional programming?

Does "Value Restriction" practically mean that there is no higher order functional programming?
I have a problem that each time I try to do a bit of HOP I get caught by a VR error. Example:
let simple (s:string)= fun rq->1
let oops= simple ""
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2= get ""
and I would like to know whether it is a problem of a prticular implementation of VR or it is a general problem that has no solution in a mutable type-infered language that doesn't include mutation in the type system.
Does “Value Restriction” mean that there is no higher order functional programming?
Absolutely not! The value restriction barely interferes with higher-order functional programming at all. What it does do is restrict some applications of polymorphic functions—not higher-order functions—at top level.
Let's look at your example.
Your problem is that oops and oops2 are both the identity function and have type forall 'a . 'a -> 'a. In other words each is a polymorphic value. But the right-hand side is not a so-called "syntactic value"; it is a function application. (A function application is not allowed to return a polymorphic value because if it were, you could construct a hacky function using mutable references and lists that would subvert the type system; that is, you could write a terminating function type type forall 'a 'b . 'a -> 'b.
Luckily in almost all practical cases, the polymorphic value in question is a function, and you can define it by eta-expanding:
let oops x = simple "" x
This idiom looks like it has some run-time cost, but depending on the inliner and optimizer, that can be got rid of by the compiler—it's just the poor typechecker that is having trouble.
The oops2 example is more troublesome because you have to pack and unpack the value constructor:
let oops2 = F(fun x -> let F f = get "" in f x)
This is quite a but more tedious, but the anonymous function fun x -> ... is a syntactic value, and F is a datatype constructor, and a constructor applied to a syntactic value is also a syntactic value, and Bob's your uncle. The packing and unpacking of F is all going to be compiled into the identity function, so oops2 is going to compile into exactly the same machine code as oops.
Things are even nastier when you want a run-time computation to return a polymorphic value like None or []. As hinted at by Nathan Sanders, you can run afoul of the value restriction with an expression as simple as rev []:
Standard ML of New Jersey v110.67 [built: Sun Oct 19 17:18:14 2008]
- val l = rev [];
stdIn:1.5-1.15 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val l = [] : ?.X1 list
-
Nothing higher-order there! And yet the value restriction applies.
In practice the value restriction presents no barrier to the definition and use of higher-order functions; you just eta-expand.
I didn't know the details of the value restriction, so I searched and found this article. Here is the relevant part:
Obviously, we aren't going to write the expression rev [] in a program, so it doesn't particularly matter that it isn't polymorphic. But what if we create a function using a function call? With curried functions, we do this all the time:
- val revlists = map rev;
Here revlists should be polymorphic, but the value restriction messes us up:
- val revlists = map rev;
stdIn:32.1-32.23 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val revlists = fn : ?.X1 list list -> ?.X1 list list
Fortunately, there is a simple trick that we can use to make revlists polymorphic. We can replace the definition of revlists with
- val revlists = (fn xs => map rev xs);
val revlists = fn : 'a list list -> 'a list list
and now everything works just fine, since (fn xs => map rev xs) is a syntactic value.
(Equivalently, we could have used the more common fun syntax:
- fun revlists xs = map rev xs;
val revlists = fn : 'a list list -> 'a list list
with the same result.) In the literature, the trick of replacing a function-valued expression e with (fn x => e x) is known as eta expansion. It has been found empirically that eta expansion usually suffices for dealing with the value restriction.
To summarise, it doesn't look like higher-order programming is restricted so much as point-free programming. This might explain some of the trouble I have when translating Haskell code to F#.
Edit: Specifically, here's how to fix your first example:
let simple (s:string)= fun rq->1
let oops= (fun x -> simple "" x) (* eta-expand oops *)
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2= get ""
I haven't figured out the second one yet because the type constructor is getting in the way.
Here is the answer to this question in the context of F#.
To summarize, in F# passing a type argument to a generic (=polymorphic) function is a run-time operation, so it is actually type-safe to generalize (as in, you will not crash at runtime). The behaviour of thusly generalized value can be surprising though.
For this particular example in F#, one can recover generalization with a type annotation and an explicit type parameter:
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2<'T> : 'T SimpleType = get ""

Resources