I'm just starting playing with idris and theorem proving in general. I can follow most of the examples of proofs of basic facts on the internet, so I wanted to try something arbitrary by my own. So, I want to write a proof term for the following basic property of map:
map : (a -> b) -> List a -> List b
prf : map id = id
Intuitively, I can imagine how the proof should work: Take an arbitrary list l and analyze the possibilities for map id l. When l is empty, it's obvious; when
l is non-empty it's based on the concept that function application preserves equality.
So, I can do something like this:
prf' : (l : List a) -> map id l = id l
It's like a for all statement. How can I turn it into a proof of the equality of the functions involved?
You can't. Idris's type theory (like Coq's and Agda's) does not support general extensionality. Given two functions f and g that "act the same", you will never be able to prove Not (f = g), but you will only be able to prove f = g if f and g are defined the same, up to alpha and eta equivalence or so. Unfortunately, things only get worse when you consider higher-order functions; there's a theorem about such in the Coq standard library, but I can't seem to find or remember it right now.
Related
I just learned about pointfree style in Haskell and how it can help tidy up the code and make it easier to read. But sometimes they can make the code a bit too terse.
So, when I should I always use pointfree style and at what scenarios should I absolutely avoid pointfree style in Haskell?
As already commented, it's a matter of taste and there will always be edge cases where both styles are equally suited (or, indeed, a partially-pointed version is best). However, there are some cases where it's clear enough:
If a pointed expression can be η-reduced just like that, it's usually a good idea to do it.
f x = g (h x)
should better be written
f = g . h
If you want to memoise some computation before accepting some function parameters, you must keep these parameters out of the scope. For instance,
linRegression :: [(Double, Double)] -> Double -> Double
linRegression ps x = a * x + b
where a, b = -- expensive calculation of regression coefficients,
-- depending on the `ps`
isn't optimal performance-wise, because the coefficients will need to be recomputed for every x value received. If you make it point-free:
linRegression :: [(Double, Double)] -> Double -> Double
linRegression ps = (+b) . (a*)
where a, b = ...
this problem doesn't arise. (Perhaps GHC will in some cases figure this out by itself, but I wouldn't rely on it.)
Often though, it is better to make it pointed nevertheless, just not with an x in the same scope as a and b but bound by a dedicated lambda:
linRegression :: [(Double, Double)] -> Double -> Double
linRegression ps = \x -> a * x + b
where a, b = ...
If the point-free version is actually longer than the pointed version, I wouldn't use it. If you need to introduce tricks to get it point-free like flip and the Monad (a->) instance and this doesn't even make it shorter, then it will almost certainly be less readable than the pointed version.
My favorite answer comes from Richard Bird's Thinking Functionally with Haskell: pointfree style helps you reason about function composition while a pointed style helps you reason about function application.
If you find that a pointfree style is awkward for writing a particular function then you generally have two options:
Use a pointed style instead. Sometimes you do want to reason about application.
Redesign your function to be compositional in nature.
In my own programs, I've found that (2) often leads to a better design and that this design can then be more clearly expressed using a pointfree style. Pointfree style is not an end goal: it is a means to achieving a more compositional design.
The uncurry function only works for functions taking two arguments:
uncurry :: (a -> b -> c) -> (a, b) -> c
If I want to uncurry functions with an arbitrary number of arguments, I could just write separate functions:
uncurry2 f (a, b) = f a b
uncurry3 f (a, b, c) = f a b c
uncurry4 f (a, b, c, d) = f a b c d
uncurry5 f (a, b, c, d, e) = f a b c d e
But this gets tedious quickly. Is there any way to generalize this, so I only have to write one function?
Try uncurryN from the tuple package. Like all forms of overloading, it's implemented using type classes. In this case by manually spelling out the instances up to 15-tuples, which should be more than enough.
Variadic functions are also possible using type classes. One example of this is Text.Printf. In this case, it's done by structural induction on the function type. Simplified, it works like this:
class Foo t
instance Foo (IO a)
instance Foo b => Foo (a -> b)
foo :: Foo
It shouldn't be hard to see that foo can be instantiated to the types IO a, a -> IO b, a -> b -> IO c and so on. QuickCheck also uses this technique.
Structural induction won't work on tuples, though, as an n-tuple is completely unrelated to a n+1-tuple, so that's why the instances have to be spelled out manually.
Finding ways to fake this sort of thing using overwrought type system tricks is one of my hobbies, so trust me when I say that the result is pretty ugly. In particular, note that tuples aren't defined recursively, so there's no real way to abstract over them directly; as far as Haskell's type system is concerned, every tuple size is completely distinct.
Any viable approach for working with tuples directly will therefore require code generation--either using TH, or an external tool as with the tuple package.
To fake it without using generated code, you have to first resort to using recursive definitions--typically right-nested pairs with a "nil" value to mark the end, either (,) and () or something equivalent to them. You may notice that this is similar to the definition of lists in terms of (:) and []--and in fact, recursively defined faux-tuples of this sort can be seen as either type-level data structures (a list of types) or as heterogeneous lists (e.g., HList works this way).
The downsides include, but are not limited to, the fact that actually using things built this way can be more awkward than it's worth, the code to implement the type system tricks is usually baffling and completely non-portable, and the end result is not necessarily equivalent anyway--there are multiple nontrivial differences between (a, (b, (c, ()))) and (a, b, c), for instance.
If you want to see how horrible it becomes you can look at the stuff I have on GitHub, particularly the bits here.
There is no straightforward way to write a single definition of uncurry that will work for different numbers of arguments.
However, it is possible to use Template Haskell to generate the many different variants that you would otherwise have to write by hand.
I am having trouble understanding what my lecturer want me to do from this question. Can anyone help explain to me what he wants me to do?
Define a higher order version of the insertion sort algorithm. That is define
functions
insertBy :: Ord b => (a->b) -> a -> [a] -> [a]
inssortBy :: Ord b => (a->b) -> [a] -> [a]
and this bit is where it got me confused:
such that inssort f l sorts the list l such that an element x comes before an elementyif f x < f y.
If you were sorting numbers, then it's clear what x < y means. But what if you were sorting letters? Or customers? Or anything else without a clear (to the computer) ordering?
So you are supposed to create a function f() that defines that ordering for the sorting procedure. That f() will take the letters or customers or whatever and will return an integer for each one that the computer can actually sort on.
At least, that's how the problem is described. I personally would have designed a predicate that accepted two items, x and y and returned a boolean if x < y. But whichever is fine.
The code wants you to rewrite the insertion sort algorithm, but using a function as a parameter - thus a higher order function.
I would like to point out that this code, typo included, seems to stem from a piece of work currently due at a certain university - I found this page while searching for "insertion sort algortihm", as I copy pasted the term out of the document as well, typo included.
Seeking code from the internet is a risky business. Might I recommend the insertion sort algorithm wikipedia entry, or the Haskell code provided in your lecture slides (you are looking for the 'insertion sort algorithm' and for 'higher-order functions), as opposed to the several queries you have placed on Stack Overflow?
Imagine a simple (made up) language where functions look like:
function f(a, b) = c + 42
where c = a * b
(Say it's a subset of Lisp that includes 'defun' and 'let'.)
Also imagine that it includes immutable objects that look like:
struct s(a, b, c = a * b)
Again analogizing to Lisp (this time a superset), say a struct definition like that would generate functions for:
make-s(a, b)
s-a(s)
s-b(s)
s-c(s)
Now, given the simple set up, it seems clear that there is a lot of similarity between what happens behind the scenes when you either call 'f' or 'make-s'. Once 'a' and 'b' are supplied at call/instantiate time, there is enough information to compute 'c'.
You could think of instantiating a struct as being like a calling a function, and then storing the resulting symbolic environment for later use when the generated accessor functions are called. Or you could think of a evaluting a function as being like creating a hidden struct and then using it as the symbolic environment with which to evaluate the final result expression.
Is my toy model so oversimplified that it's useless? Or is it actually a helpful way to think about how real languages work? Are there any real languages/implementations that someone without a CS background but with an interest in programming languages (i.e. me) should learn more about in order to explore this concept?
Thanks.
EDIT: Thanks for the answers so far. To elaborate a little, I guess what I'm wondering is if there are any real languages where it's the case that people learning the language are told e.g. "you should think of objects as being essentially closures". Or if there are any real language implementations where it's the case that instantiating an object and calling a function actually share some common (non-trivial, i.e. not just library calls) code or data structures.
Does the analogy I'm making, which I know others have made before, go any deeper than mere analogy in any real situations?
You can't get much purer than lambda calculus: http://en.wikipedia.org/wiki/Lambda_calculus. Lambda calculus is in fact so pure, it only has functions!
A standard way of implementing a pair in lambda calculus is like so:
pair = fn a: fn b: fn x: x a b
first = fn a: fn b: a
second = fn a: fn b: b
So pair a b, what you might call a "struct", is actually a function (fn x: x a b). But it's a special type of function called a closure. A closure is essentially a function (fn x: x a b) plus values for all of the "free" variables (in this case, a and b).
So yes, instantiating a "struct" is like calling a function, but more importantly, the actual "struct" itself is like a special type of function (a closure).
If you think about how you would implement a lambda calculus interpreter, you can see the symmetry from the other side: you could implement a closure as an expression plus a struct containing the values of all the free variables.
Sorry if this is all obvious and you just wanted some real world example...
Both f and make-s are functions, but the resemblance doesn't go much further. Applying f calls the function and executes its code; applying make-s creates a structure.
In most language implementations and modelizations, make-s is a different kind of object from f: f is a closure, whereas make-s is a constructor (in the functional languages and logic meaning, which is close to the object oriented languages meaning).
If you like to think in an object-oriented way, both f and make-s have an apply method, but they have completely different implementations of this method.
If you like to think in terms of the underlying logic, f and make-s have a type build on the samme type constructor (the function type constructor), but they are constructed in different ways and have different destruction rules (function application vs. constructor application).
If you'd like to understand that last paragraph, I recommend Types and Programming Languages by Benjamin C. Pierce. Structures are discussed in §11.8.
Is my toy model so oversimplified that it's useless?
Essentially, yes. Your simplified model basically boils down to saying that each of these operations involves performing a computation and putting the result somewhere. But that is so general, it covers anything that a computer does. If you didn't perform a computation, you wouldn't be doing anything useful. If you didn't put the result somewhere, you would have done work for nothing as you have no way to get the result. So anything useful you do with a computer, from adding two registers together, to fetching a web page, could be modeled as performing a computation and putting the result somewhere that it can be accessed later.
There is a relationship between objects and closures. http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html
The following creates what some might call a function, and others might call an object:
Taken from SICP ( http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-21.html )
(define (make-account balance)
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))
(define (deposit amount)
(set! balance (+ balance amount))
balance)
(define (dispatch m)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request -- MAKE-ACCOUNT"
m))))
dispatch)
Which are the uses for id function in Haskell?
It's useful as an argument to higher order functions (functions which take functions as arguments), where you want some particular value left unchanged.
Example 1: Leave a value alone if it is in a Just, otherwise, return a default of 7.
Prelude Data.Maybe> :t maybe
maybe :: b -> (a -> b) -> Maybe a -> b
Prelude Data.Maybe> maybe 7 id (Just 2)
2
Example 2: building up a function via a fold:
Prelude Data.Maybe> :t foldr (.) id [(+2), (*7)]
:: (Num a) => a -> a
Prelude Data.Maybe> let f = foldr (.) id [(+2), (*7)]
Prelude Data.Maybe> f 7
51
We built a new function f by folding a list of functions together with (.), using id as the base case.
Example 3: the base case for functions as monoids (simplified).
instance Monoid (a -> a) where
mempty = id
f `mappend` g = (f . g)
Similar to our example with fold, functions can be treated as concatenable values, with id serving for the empty case, and (.) as append.
Example 4: a trivial hash function.
Data.HashTable> h <- new (==) id :: IO (HashTable Data.Int.Int32 Int)
Data.HashTable> insert h 7 2
Data.HashTable> Data.HashTable.lookup h 7
Just 2
Hashtables require a hashing function. But what if your key is already hashed? Then pass the id function, to fill in as your hashing method, with zero performance overhead.
If you manipulate numbers, particularly with addition and multiplication, you'll have noticed the usefulness of 0 and 1. Likewise, if you manipulate lists, the empty list turns out to be quite handy. Similarly, if you manipulate functions (very common in functional programming), you'll come to notice the same sort of usefulness of id.
In functional languages, functions are first class values
that you can pass as a parameter.
So one of the most common uses of id comes up when
you pass a function as a
parameter to another function to tell it what to do.
One of the choices of what to do is likely to be
"just leave it alone" - in that case, you pass id
as the parameter.
Suppose you're searching for some kind of solution to a puzzle where you make a move at each turn. You start with a candidate position pos. At each stage there is a list of possible transformations you could make to pos (eg. sliding a piece in the puzzle). In a functional language it's natural to represent transformations as functions so now you can make a list of moves using a list of functions. If "doing nothing" is a legal move in this puzzle, then you would represent that with id. If you didn't do that then you'd need to handle "doing nothing" as a special case that works differently from "doing something". By using id you can handle all cases uniformly in a single list.
This is probably the reason why almost all uses of id exist. To handle "doing nothing" uniformly with "doing something".
For a different sort of answer:
I'll often do this when chaining multiple functions via composition:
foo = id
. bar
. baz
. etc
over
foo = bar
. baz
. etc
It keeps things easier to edit. One can do similar things with other 'zero' elements, such as
foo = return
>>= bar
>>= baz
foos = []
++ bars
++ bazs
Since we are finding nice applications of id. Here, have a palindrome :)
import Control.Applicative
pal :: [a] -> [a]
pal = (++) <$> id <*> reverse
Imagine you are a computer, i.e. you can execute a sequence of steps. Then if I want you to stay in your current state, but I always have to give you an instruction (I cannot just mute and let the time pass), what instruction do I give you? Id is the function created for that, for returning the argument unchanged (in the case of the previous computer the argument would be its state) and for having a name for it. That necessity appears only when you have high order functions, when you operate with functions without considering what's inside them, that forces you to represent symbolically even the "do nothing" implementation. Analogously 0 seen as a quantity of something, is a symbol for the absence of quantity. Actually in Algebra both 0 and id are considered the neutral elements of the operations + and ∘ (function composition) respectively, or more formally:
for all x of type number:
0 + x = x
x + 0 = x
for all f of type function:
id ∘ f = f
f ∘ id = f
I can also help improve your golf score. Instead of using
($)
you can save a single character by using id.
e.g.
zipWith id [(+1), succ] [2,3,4]
An interesting, more than useful result.
Whenever you need to have a function somewhere, but want to do more than just hold its place (with 'undefined' as an example).
It's also useful, as (soon-to-be) Dr. Stewart mentioned above, for when you need to pass a function as an argument to another function:
join = (>>= id)
or as the result of a function:
let f = id in f 10
(presumably, you will edit the above function later to do something more "interesting"... ;)
As others have mentioned, id is a wonderful place-holder for when you need a function somewhere.