In Isabelle/HOL, the following axiomatizations can be found
axiomatization The :: "('a ⇒ bool) ⇒ 'a"
axiomatization undefined :: 'a
Is there a reason that one couldn't use
definition "undefined ≡ The (λx. False)"
or is this just a historic artifact? It seems that the current way leads to "different" notions of undefinedness. I stumbled upon this when I defined something along the lines of
definition "of_interest y ≡ (THE x. foobar x y)"
and wanted to prove the (in hindsight foolish) sanity-check
lemma "(∄x. foobar x y) ⟹ of_interest y = undefined"
which obviously doesn't work in the current state, but should go through with the above definition of undefined.
By using the axiomatization mechanism you clearly state that you cannot assume anything about undefined :: 'a but that it's an arbitrary but unknown value of type 'a. On the contrary, by using your definition, you now know a bit more about undefined, namely that it's the value to which The maps λx. False (the same applies for Eps (λx. True) and similar definitions). For example, with your definition you can prove that The (λx. False) = undefined, which you cannot prove using the axiomatization.
Related
I am looking at Haskell elemIndex function:
elemIndex :: Eq a => a -> [a] -> Maybe Int
What does Maybe mean in this definition? Sometimes when I call it, the output has a Just or a Nothing What does it mean? How can I interpret this if I were to use folds?
First question:
What does it mean?
This means that the returned value is either an index (Int) or Nothing.
from the docs:
The elemIndex function returns the index of the first element in the given list which is equal (by ==) to the query element, or Nothing if there is no such element.
The second question:
How can I interpret this if I were to use folds?
I'm not sure there is enough context to the "were to use folds" part. But, there are at least 2 ways to use this function:
case analysis, were you state what to return in each case:
case elemIndex xs of
Just x -> f x -- apply function f to x.
Nothing -> undefined -- do something here, e.g. give a default value.
use function maybe:
maybe defaultValue f (elemIndex xs)
Maybe is a sum type.
Sum type is any type that has multiple possible representations.
For example:
data Bool = False | True
Bool can represented as True or False. The same goes with Maybe.
data Maybe a = Nothing | Just a
The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing)
elemIndex :: Eq a => a -> [a] -> Maybe Int
The elemIndex function returns the index of the first element in the given list which is equal (by ==) to the query element, or Nothing if there is no such element.
Lets compare it to the indexOf function
What are the possible values of this method?
The index of the element in the array in case it was found (lets say 2).
-1 in case it was not found.
Another way to represent it:
Return a number in case it was found - Just 2.
Instead of returning magic numbers like -1 we can return a value that represents the
option of a failure - Nothing.
Regarding "How can I interpret this if I were to use folds", I do not have enough information to understand the question.
Maybe is a type constructor.
Int is a type. Maybe Int is a type.
String is a type. Maybe String is a type.
For any type a, Maybe a is a type. Its values come in two varieties: either Nothing or Just x where x is a value of type a (we write: x :: a):
x :: a
----------------- ------------------
Just x :: Maybe a Nothing :: Maybe a
In the first rule, the a in both the type of the value x :: a and the type of the value Just x :: Maybe a is the same. Thus if we know the type of x we know the type of Just x; and vice versa.
In the second rule, nothing in the value Nothing itself determines the a in its type. The determination will be made according to how that value is used, i.e. from the context of its usage, from its call site.
As to the fold implementation of elemIndex, it could be for example
elemIndex_asFold :: Eq a => a -> [a] -> Maybe Int
elemIndex_asFold x0 = foldr g Nothing
where
g x r | x == x0 = Just x
| else = r
This is a bit theoretical question. We can define fx but seemingly not fx':
Function fx {A} (x:A) (f:A->Type) (g:Type->f x): f x := g (f x).
Definition fx' {A} (x:A) (f:A->Type): f x.
In a way, this makes sense, as one cannot prove from the f and x that f has been (or will be) applied to x. But we can apply f to x to get something of type Type:
assert (h := f x).
This seems puzzling: one can apply f to x but still can't obtain a witness y: f x that he has done so.
The only explanation I can think of is this: as a type, f x is an application, as a term, it's just a type. We cannot infer a past application from a type; similarly, we cannot infer a future application from a function and its potential argument. As for (the instance of) applying itself, it isn't a stage in a proof, so we cannot have a witness of it. But I'm just guessing. The question:
Is it possible to define fx'? If yes, how; if no, why (please give a theoretical explanation)
First, a direct answer to your question: no, it is not possible to define fx'. According to your snippet, fx' should have type
forall (A : Type) (x : A) (f : A -> Type), f x.
It is not hard to see that the existence of fx' implies a contradiction, as the following script shows.
Section Contra.
Variable fx' : forall (A : Type) (x : A) (f : A -> Type), f x.
Lemma contra : False.
Proof.
exact (fx' unit tt (fun x => False)).
Qed.
End Contra.
What happened here? The type of fx' says that for any family of types f indexed by a type A, we can produce an element of f x, where x is arbitrary. In particular, we can take f to be a constant family of types (fun x => False), in which case f x is the same thing as False. (Note that False, besides being a member of Prop, is also a member of Type.)
Now, given your question, I think you are slightly confused by the meaning of types and propositions in Coq. You said:
This seems puzzling: one can apply f to x but still can't obtain a
witness y: f x that he has done so.
The fact that we can apply f to x simply means that the expression f x has a valid type, which, in this case, is Type. In other words, Coq shows that f x : Type. But having a type is a different thing from being inhabited: when f and x are arbitrary, it is not possible to build a term y such that y : f x. In particular, we have False : Type, but there is no way we can build a term p with p : False, because that would mean that Coq's logic is inconsistent.
I am trying to write a simple tool in Haskell as a learning exercise, and have encountered something that I cannot figure out. Here is a simple sample illustrating it.
idMap :: a -> a
idMap x = map id x
main = do
print $ idMap [1, 2]
According to my understanding, this example should compile and print [1, 2] when run. However, if fails to compile with the following message:
source_file.hs:2:18: error:
• Couldn't match expected type ‘[b0]’ with actual type ‘a’
‘a’ is a rigid type variable bound by
the type signature for:
idMap :: forall a. a -> a
at source_file.hs:1:10
• In the second argument of ‘map’, namely ‘x’
In the expression: map id x
In an equation for ‘idMap’: idMap x = map id x
• Relevant bindings include
x :: a
(bound at source_file.hs:2:7)
idMap :: a -> a
(bound at source_file.hs:2:1)
It kind of makes sense, given that the signature of map is (a -> b) -> [a] -> [b] so the input type is not necessarily the same as the output type, but the signature of id is a -> a so surely it follows that map id would have a signature of (a -> a) -> [a] -> [a]?
The second part I don't really understand is why this is an exception given that all the types (a and b as above) are Integer. It would make sense to me that since the signature of idMap is a -> a, there should only be a compile exception if it is used in a situation where the output type is expected to be different from input type.
Finally, how would I make this code actually work? My real code is a little more complicated and I am relying on the output type matching the input type elsewhere in the code so I don't want to change the signature of idMap, I want to know what I would need to do to write a function with that signature.
You are applying idMap to a list. Therefore, we know the argument type should be some list type. Further, you expect the return type to be a list ([1,2]), so the return type should be a list as well. Since the id function is fully polymorphic (a -> a), we can map it over a list of any type a and return a list of items of the same type a. Thus, your final type signature should be [a] -> [a].
Regarding your second question, while it's true that the argument type and return type are both the same, the type as a -> a is not true for all types a. Based on the type signature of map, idMap must accept a list argument. We can declare type signatures for functions that are more constrained than necessary, but not less.
Your implementation of idMap...
idMap x = map id x
... involves applying map id on x. As a consequence, x must be a list.
GHCi> :t map id
map id :: [b] -> [b]
This will work just fine:
idMap :: [a] -> [a]
idMap x = map id x
Note that, thanks to the use of id, x and idMap x do have the same type (as do their elements), as you expected.
[...] a pair of functions tofun : int -> ('a -> 'a) and fromfun : ('a -> 'a) ->
int such that (fromfun o tofun) n evaluates to n for every n : int.
Anyone able to explain to me what this is actually asking for? I'm looking for more of an explanation of that than an actual solution to this.
What this is asking for is:
1) A higher-order function tofun which when given an integer returns a polymorphic function, one which has type 'a->'a, meaning that it can be applied to values of any type, returning a value of the same type. An example of such a function is:
- fun id x = x;
val id = fn : 'a -> 'a
for example, id "cat" = "cat" and id () = (). The later value is of type unit, which is a type with only 1 value. Note that there is only 1 total function from unit to unit (namely, id or something equivalent). This underscores the difficulty with coming up with defining tofun: it returns a function of type 'a -> 'a, and other than the identity function it is hard to think of other functions. On the other hand -- such functions can fail to terminate or can raise an error and still have type 'a -> 'a.
2) fromfun is supposed to take a function of type 'a ->'a and return an integer. So e.g. fromfun id might evaluate to 0 (or if you want to get tricky it might never terminate or it might raise an error)
3) These are supposed to be inverses of each other so that, e.g. fromfun (tofun 5) needs to evaluate to 5.
Intuitively, this should be impossible in a sufficiently pure functional language. If it is possible in SML, my guess is that it would be by using some of the impure features of SML (which allow for side effects) to violate referential transparency. Or, the trick might involve raising and handling errors (which is also an impure feature of SML). If you find an answer which works in SML it would be interesting to see if it could be translated to the annoyingly pure functional language Haskell. My guess is that it wouldn't translate.
You can devise the following property:
fun prop_inverse f g n = (f o g) n = n
And with definitions for tofun and fromfun,
fun tofun n = ...
fun fromfun f = ...
You can test that they uphold the property:
val prop_test_1 =
List.all
(fn i => prop_inverse fromfun tofun i handle _ => false)
[0, ~1, 1, valOf Int.maxInt, valOf Int.minInt]
And as John suggests, those functions must be impure. I'd also go with exceptions.
I would like to implement a type-parametrized function as per excersize on page 72 of the book (implement forall using filter):
def forallA[B <: A](xs:List[A])(f:A => B) : List[B] = {
xs.filter(x => true) match {
case Nil => Nil
case y :: ys => f(y) :: forallA(ys)(f)
}
}
However, the compiler(2.9.1) complains about the type A being undefined. Clearly that should not be the case, since multiple examples in the same book use this syntax. The issue can be cured by changnig the function type parameter to [A, B <: A]. Am I doing something wrong, or is it again, a terrific change in Scala's syntax specification? If so, I am, frankfully, tired of bombing SO with such stupid questions on every second excersize. Could anyone recommend a book that clearly reflects the current order of things?
You already gave the answer: If you want to bound the type parameter B with another type parameter A, you have to add this to the list of type parameters:
def forall[A, B <: A](...)(...) = ...
Else you are referring to something undefined. Maybe it helps if you think of type parameters like usual (method) parameters. How should something like the following compile:
def add(x: Int) = x + y
Here the parameter y is undefined, just like in your case A was undefined.