Curry-Howard isomorphism definitions in Coq using fun - set

I'm having some issues with defining in Coq, more specifically when defining using the CHI. I have managed to gain the understanding of basic principals but when I try to define this"
((A -> (A -> C)) * ((A -> C) -> A)) -> C :=
I get nowhere due to the fact it keeps telling me:
"Error: The type of this term is a product while it is expected to be "C".
I have already tried the usual tactics I have used earlier in my script and I'm convinced this has to be solved using the same methods (fun) however everything I seem to be trying ends in that error message. Any tips?

It seems you are defining a function that takes as input:
a function of type A -> (A -> C): given an object of type A, it gives back a function of type A -> C.
a function of type (A -> C) -> A: given a function of type A -> C, it gives back an object of type A.
You are trying to build an object of type C which I don't see how you will managed to do it. However you can build an object of type A by combining the two functions you have as input.
Hope it helps,
V.

Related

Are both of these ways correct to do beta reduction?

First way: (λz.(λx.x) z) -> (x)[x->z] -> (λz.z)
Second way: (λz.(λx.x) z) -> (λx.x)[z->z] -> (λx.x)
Any lambda calculus online calculator I'm using only provides the first way as a solution, whatever strategy I set on it, and I can't seem to figure out why the second way is not correct.

Is F# Constructed Type syntax special?

I was curious about F#'s "constructed type" syntax. It's documented here.
type-argument generic-type-name
or
generic-type-name
With the following examples:
int option
string list
int ref
option<int>
list<string>
ref<int>
Dictionary<int, string>
I was curious if there's anything special about the "backwards" syntax, with the parameter before the type, or if it's just sugar for generic types with one parameter. The following is valid:
type 'a MyOption = // MyOption<'a> also works
| MySome of 'a
| MyNone
But I could not get it to work with multiple type parameters. Why do F# developers prefer this syntax for types with one parameter? Is it possible or desirable to make it work with two?
The backwards syntax is a legacy from OCaml. Personally, I never use it. If you really want to, you can make it work with multiple type arguments like this:
type MyMap = (int, string) Map
However, this generates a pointed warning (that might soon become an error):
This construct is for ML compatibility. The syntax '(typ,...,typ) ident' is not used in F# code. Consider using 'ident<typ,...,typ>' instead. You can disable this warning by using '--mlcompatibility' or '--nowarn:62'.
Bottom line, I would recommend always using .NET syntax instead: MyOption<'a> instead of 'a MyOption.
Why do F# developers prefer this syntax for types with one parameter?
Not all of us do. I love F# and am in awe of it, but find the OCaml style distracting.
It gets especially confusing when the two styles are mixed - compare the readability of Async<Result<int,string list>> list with that of List<Async<Result<int,List<string>>>>.
Here is a thread with some arguments from both sides from fslang suggestions, which I think led to the deprecation of OCaml-style for everything but list, option and a few others.
I find it regrettable that the OCaml style is specified as the preferred option (for these types) in the various style guides, and used throughout the core libraries, while there is such a strong drive to make the language more accessible to newcomers. It definitely adds to the learning curve, as documented in this question,
and here,
here,
here,
here,
here.
Is it possible or desirable to make [OCaml style naming] work with two [type parameters]?
I think a better question is: "Is it possible to only use .NET style?".
Unfortunately the tooling shows types the way they are declared, and the core libraries consistently use OCaml style. I have asked Rider about always showing declarations .NET style in code vision, who referred me to FSharp compiler services. I have not (yet) investigated that avenue further.
In our own code we have taken to overriding the OCaml signatures of functions that ship with F# and other libraries as we come across them, for example:
[<AutoOpen>]
module NoCaml =
module List =
/// Returns a new collection containing only the elements of the collection for which the given predicate returns "true"
let filter = List.filter : ('a -> bool) -> List<'a> -> List<'a>
/// val groupBy : projection:('T -> 'Key) -> list:'T list -> ('Key * 'T list) list (requires equality and equality) 'T is 'a 'Key is 'b Applies a key-generating function to each element of a list and yields a list of unique keys. Each unique key contains a list of all elements that match to this key.
let groupBy = List.groupBy : ('a -> 'b) -> List<'a> -> List<'b * List<'a>>
// etc.
This solves the problem in almost all cases (some exceptions like list construction using [] remain, and need to be overridden at the point of declaration).
I'm not sure what influence this has on performance at runtime - hopefully the extra function calls are optimised away.

Haskell: is it possible to output type as a part of a program?

To help with debugging and writing programs in Haskell, I am thinking about ability of Haskell programs to output types of variables as part of the program. For example, I have following code:
listHEADFiles :: ReaderT LgRepo IO ()
listHEADFiles = do
ref <- resolveReference $ T.pack "HEAD"
case ref of
Nothing -> fail "Could not resolve reference named 'HEAD'"
Just reference -> do
obj <- lookupObject reference
case obj of
CommitObj commit -> do
objects <- listAllObjects Nothing (commitOid commit)
for_ objects (\case
TreeObjOid toOid -> do
tree <- lookupTree toOid
treeEntries <- sourceTreeEntries tree
entries <- lift $ treeEntries
outputTypeOf entries
)
_ -> fail "'HEAD' is not a commit object"
I want to output type of variable entries because I fail to understand what exactly happens after I lift the value. I can go to documentation, but it always perplexes me to calculate it by hand. I would like to know for sure what type it is when my program is executed. In other words, I want functionality of :t in ghci as a part of my program. Is it possible?
You don't really want your program to output a type: you want the compiler to output a type when it compiles your program. The feature you're looking for is Partial type signatures. The idea is you put an incomplete signature on an expression, and you get out a compiler "error" telling you how to fill in the blanks. If you have no idea at all of the type, an acceptable incomplete signature would be just _:
(entries :: _) <- lift $ treeEntries

What is the bottom type?

In wikipedia, the bottom type is simply defined as "the type that has no values". However, if b is this empty type, then the product type (b,b) has no values either, but seems different from b. I agree bottom is uninhabited, but I don't think this property suffices to define it.
By the Curry-Howard correspondence, bottom is associated to mathematical falsity. Now there is a logical principle stating that from False follows any proposition. By Curry-Howard, that means the type forall a. bottom -> a is inhabited, ie there exists a family of functions f :: forall a. bottom -> a.
What are those functions f ? Do they help define bottom, maybe as the infinite product of all types forall a. a ?
In Math
Bottom is a type that has no value. That is : any empty type can play the bottom role.
Those f :: forall a . Bottom -> a functions are the empty functions. "empty" in the set theoretical definition of functions.
In Programming
Dedicating a concrete empty type to have it as bottom by a programming language base library is for convenience. Readability and compatibility of code benefits from everyone using the same empty type as bottom.
In Haskell
Let us refer to them with the more friendly names "Bottom" -> "Void", "f" -> "absurd".
{-# LANGUAGE EmptyDataDecls #-}
data Void
This definition does not contain any constructors => an instance of it can not be created => it is empty.
absurd :: Bottom -> a
absurd = \ case {}
In the case expression we do not have to handle any cases because there are none.
They are already defined in package base

Typing the Y combinator

http://muaddibspace.blogspot.com/2008/01/type-inference-for-simply-typed-lambda.html is a concise definition of the simply typed lambda calculus in Prolog.
It looks okay, but then he purports to assign a type to the Y combinator... whereas in a very real sense the entire purpose of adding types to lambda calculus is to refuse to assign a type to things like the Y combinator.
Can anyone see exactly where his error or -- more likely -- my misunderstanding is?
The Y combinator in its basic form
Y f = (\x -> f (x x)) (\x -> f (x x))
just cannot be typed using the simple type system proposed in the article.
There are other, much easier but meaningful examples that cannot be typed on that level:
Take e.g.
test f = (f 1, f "Hello")
This obviously works for test (\x -> x) but we cannot give the higher-ranked type that was required here, namely
test :: (∀a . a -> a) -> (Int, String)
But even in more advanced type systems like the GHCI extensions of Haskell which allow the above, Y is still hard to type.
So, given the possibility of recursion, we can just define and work using the fix combinator
fix f = f (fix f)
with fix :: (a -> a) -> a
Typing should disallow self application, it should not be possible to find a type for (t t). If it where possible then t would have a type A -> B, and we would have A = A -> B. Since self application is part of Y combinator, its also not possible to give a type to it.
Unfortunately many Prolog systems allow a solution for A = A -> B. This happens on many grounds, either the Prolog system allows circular terms, then the unification will succeed and the resulting bindings can even further be processed. Or the Prolog system does not allow circular terms, then it depends on whether it implements an occurs check. If the occurs check is on, then unification will not succeed. If the occurs check is off, then the unification might succeed but the resulting bindings can not further be processed, most likely leading to stack overflow in printing or further unifications.
So I guess a circular unification of this type happens in the given code by the used Prolog system and it gets unnoticed.
One way to solve the issue would be to either switch on the occurs check or to replace any of the occuring unifications in the code by an explicit call to unify_with_occurs_check/2.
Best Regards
P.S.: The following Prolog code works better:
/**
* Simple type inference for lambda expression.
*
* Lambda expressions have the following syntax:
* apply(A,B): The application.
* [X]>>A: The abstraction.
* X: A variable.
*
* Type expressions have the following syntax:
* A>B: Function domain
*
* To be on the save side, we use some unify_with_occurs_check/2.
*/
find(X,[Y-S|_],S) :- X==Y, !.
find(X,[_|C],S) :- find(X,C,S).
typed(C,X,T) :- var(X), !, find(X,C,S),
unify_with_occurs_check(S,T).
typed(C,[X]>>A,S>T) :- typed([X-S|C],A,T).
typed(C,apply(A,B),R) :- typed(C,A,S>R), typed(C,B,T),
unify_with_occurs_check(S,T).
Here are some sample runs:
Jekejeke Prolog, Development Environment 0.8.7
(c) 1985-2011, XLOG Technologies GmbH, Switzerland
?- typed([F-A,G-B],apply(F,G),C).
A = B > C
?- typed([F-A],apply(F,F),B).
No
?- typed([],[X]>>([Y]>>apply(Y,X)),T).
T = _T > ((_T > _Q) > _Q)

Resources