I'm new to functional programming.
So the terms cons appends an element to the front of the list. Where
cons ≜ λx:λl:λc:λn: c x (l c n)
How should I go about proving that cons works correctly using beta reduction for a sample function call? For example reducing cons 3 [2,1] to [3,2,1]?
Is there a formula like for the arithmetic operations in lambda calculus? I'm a bit confused on how to approach this compared to an arithmetic operation (i.e. addition or multiplication).
Thanks.
cons ≜ λx:λl:λc:λn: c x (l c n) means that
cons x l c n =
c x (l c n)
(in functional / applicative / combinatory notation). So
cons 3 [2,1] c n =
= c 3 ([2,1] c n)
and what is [2,1] if not just shortcut notation for cons 2 [1] so that we continue
= c 3 (cons 2 [1] c n)
= c 3 (c 2 ([1] c n))
= c 3 (c 2 (cons 1 [] c n))
= c 3 (c 2 (c 1 ([] c n)))
So there's no reduction from cons 3 [2,1] to [3,2,1]; [3,2,1] is cons 3 [2,1]. And [2,1] is cons 2 [1], and [1] is cons 1 [].
The list cons x xs, when supplied with c and n arguments, will turn into c x (xs c n), and so will xs, in its turn; so any list's elements are used in the chain of applications of c on top one another.
And what should [] c n turn into? It has nothing in it to put through the c applications -- those are to be applied to a list's elements, and [] has none. So the only reasonable thing to do (and I'm sure you're already given that definition) is to turn [] c n into just n:
cons 3 [2,1] c n =
= c 3 (c 2 (c 1 ([] c n)))
= c 3 (c 2 (c 1 n ))
whatever c and n are.
And that's that.
This code is from an assignment I already solved. Still I am trying to figure out if I could fix my initial attempt.
So we got this tree structure and the foldTree function.
data Tree a = Leaf a
| Node (Tree a) (Tree a)
foldTree :: (b -> b -> b) -> (a -> b) -> Tree a -> b
foldTree op f (Leaf x) = f x
foldTree op f (Node l r) = foldTree op f l `op` foldTree op f r
Now mapTree has to be implemented using foldTree.
I got it done this way.
mapTree :: (a -> b) -> Tree a -> Tree b
mapTree' f tree = foldTree Node (Leaf . f) tree
What I initially came up with and still don't get to work is this:
mapTree :: (a -> b) -> Tree a -> Tree b
mapTree f tree = foldTree Node transFunc tree
where transFunc :: Tree a -> Tree b
transFunc (Leaf x) = Leaf (f x)
transFunc (Node l r) = Node (transFunc l) (transFunc r)
The second function is wrong because of its type: Tree a -> Tree b while foldTree expects it to be a -> b where a is taken from Tree a. b is required by mapTree to be Tree b therefore the third argument to foldTree should be of type a -> Tree b.
So the simplest fixed version of your transFunc is:
mapTree :: forall a b. (a -> b) -> Tree a -> Tree b
mapTree f tree = foldTree Node transFunc tree
where transFunc :: a -> Tree b
transFunc x = Leaf (f x)
Note that you need to enable ScopedTypeVariables extension to compile it.
And that version of transFunc is an equivalent of your working solution: (Leaf . f)
Usually test which contain question about SML have questions that ask you to find the signature/type of a function.
For example - What is the type of the following function:
fun foo f g x y = f (f x (g x) y) y;
Solution:
val foo = fn : ('a -> 'b -> 'b -> 'a) -> ('a -> 'b) -> 'a -> 'b -> 'b -> 'a
I was wondering if there is a good algorithm I could follow in order to solve those kind of questions. Every time I try to solve one of those, I get confused and fail.
Start with what you know, then figure out a bit here and a bit there until there are no unknowns.
Here is one possibility:
Call the unknown types FOO, F, G, X, and Y, respectively.
Then look for something small and easy and start assigning types.
(g x)
is clearly an application of a function to one argument.
Set X = a and G = a -> b.
Then look at the enclosing expression:
(f x (g x) y)
| |
v v
a b
So far, we know that F = a -> b -> Y -> C, for some C.
Go outwards again:
f (f x (g x) y) y
Since both x and (f x (g x) y) are first arguments to f, they must be the same type a, and the same idea applies to y and (g x), giving them the type b.
So, F = a -> b -> b -> a and, since the outer f is only given two arguments, the type of the right-hand side must be b -> a.
Thus
X = a
Y = b
G = a -> b
F = a -> b -> b -> a
FOO = (a -> b -> b -> a) -> (a -> b) -> a -> b -> (b -> a)
And, since arrows associate to the right, FOO is equivalent to
(a -> b -> b -> a) -> (a -> b) -> a -> b -> b -> a
There are several ways to derive the type of a function depending on how close to the compiler's algorithm you want to go and how much you want to cut corners with intuition, which can come handy in practice and perhaps in exams, depending on the focus of the exam.
An example by Ionuț G. Stan cuts very few corners, and has a quite verbose notation. This mechanical approach is very safe, spells out everything and takes some time.
This current example by molbdnilo takes a middle ground and does some equational reasoning, but also relies on some level of intuition. I think this is generally the way you want to be able to do it, since it takes less time and space by hand.
An example by me links to various other examples for a diversity in practical approaches.
I have the following data type and example equation that I want to transform with a futumorphism...
import Matryoshka as M
import Data.Functor.Nu (Nu(..), observe, unfold)
data ArithmeticF a
= Mult a a
| Div a a
| Add a a
| Num Number
type Arithmetic = Nu ArithmeticF
derive instance functorArith :: Functor ArithmeticF
equation :: Arithmetic
equation = (div (n 3.0) (n 4.0)) `add` (div (n 3.0) (n 4.0))
mult :: Arithmetic -> Arithmetic -> Arithmetic
mult a b = M.embed $ Mult a b
div :: Arithmetic -> Arithmetic -> Arithmetic
div a b = M.embed $ Div a b
add :: Arithmetic -> Arithmetic -> Arithmetic
add a b = M.embed $ Add a b
n :: Number -> Arithmetic
n a = M.embed $ Num a
Using futu
this is my attempt at writing a function to factor out (Div (Num 1.0) (Num 4.0)) from the equation.
In the end I want the resulting tree to be (Mult (Div (Num 1.0) (Num 4.0)) (Add (Num 3.0) (Num 3.0))).
This function type checks but I must be doing something wrong, since it doesn't evaluate when I run it.
solve :: Arithmetic -> Number
solve = M.cata algebra
simplify :: Arithmetic -> Arithmetic
simplify s = M.futu factor s
factor :: GCoalgebra (Free ArithmeticF) ArithmeticF Arithmetic
factor s = case M.project s of
(Add a b) ->
case (Tuple (M.project a) (M.project b)) of
(Tuple (Div c d) (Div e f)) -> do
let dd = solve d
let ff = solve f
if dd == ff
then
Mult
(liftF $ observe (unfold dd (\m -> Div 1.0 dd )))
(liftF $ observe (unfold c (\g -> Add c e )))
else Add (liftF $ observe a) (liftF $ observe b)
_ -> Add (liftF $ observe a) (liftF $ observe b)
(Div a b) -> Div (liftF $ observe a) (liftF $ observe b)
(Mult a b) -> Mult (liftF $ observe a) (liftF $ observe b)
(Num a) -> (Num a)
main = log $ M.cata show (simplify equation)
I seem to have missed the connection between Recursive/Corecursive and Nu's observe and unfold methods.
class (Functor f) <= Recursive t f | t -> f where
project :: t -> f t
instance recursiveNu ∷ Functor f ⇒ Recursive (Nu f) f where
project = observe
class (Functor f) <= Corecursive t f | t -> f where
embed :: f t -> t
instance corecursiveNu ∷ Functor f ⇒ Corecursive (Nu f) f where
embed = flip unfold (map observe)
In the end I was able to write futu's GCoalgebra like so:
factor :: GCoalgebra (Free ArithmeticF) ArithmeticF Arithmetic
factor s = case M.project s of
(Add a b) -> case Tuple (observe a) (observe b) of
Tuple (Div c d) (Div e f) ->
if solve d == solve f -- observe d == observe f
then Mult (liftF $ Div (M.embed $ Num 1.0) d) (liftF $ Add c e)
else Add (liftF $ observe a) (liftF $ observe b)
_ -> Add (liftF $ observe a) (liftF $ observe b)
(Div a b) -> Div (liftF $ observe a) (liftF $ observe b)
(Mult a b) -> Mult (liftF $ observe a) (liftF $ observe b)
(Num a) -> (Num a)
For some reason, I could make a catchall case like a -> M.project a, so there's some verbosity in handling the default cases. There might be a better way to do this.
In pure functional languages like Haskell, is there an algorithm to get the inverse of a function, (edit) when it is bijective? And is there a specific way to program your function so it is?
In some cases, yes! There's a beautiful paper called Bidirectionalization for Free! which discusses a few cases -- when your function is sufficiently polymorphic -- where it is possible, completely automatically to derive an inverse function. (It also discusses what makes the problem hard when the functions are not polymorphic.)
What you get out in the case your function is invertible is the inverse (with a spurious input); in other cases, you get a function which tries to "merge" an old input value and a new output value.
No, it's not possible in general.
Proof: consider bijective functions of type
type F = [Bit] -> [Bit]
with
data Bit = B0 | B1
Assume we have an inverter inv :: F -> F such that inv f . f ≡ id. Say we have tested it for the function f = id, by confirming that
inv f (repeat B0) -> (B0 : ls)
Since this first B0 in the output must have come after some finite time, we have an upper bound n on both the depth to which inv had actually evaluated our test input to obtain this result, as well as the number of times it can have called f. Define now a family of functions
g j (B1 : B0 : ... (n+j times) ... B0 : ls)
= B0 : ... (n+j times) ... B0 : B1 : ls
g j (B0 : ... (n+j times) ... B0 : B1 : ls)
= B1 : B0 : ... (n+j times) ... B0 : ls
g j l = l
Clearly, for all 0<j≤n, g j is a bijection, in fact self-inverse. So we should be able to confirm
inv (g j) (replicate (n+j) B0 ++ B1 : repeat B0) -> (B1 : ls)
but to fulfill this, inv (g j) would have needed to either
evaluate g j (B1 : repeat B0) to a depth of n+j > n
evaluate head $ g j l for at least n different lists matching replicate (n+j) B0 ++ B1 : ls
Up to that point, at least one of the g j is indistinguishable from f, and since inv f hadn't done either of these evaluations, inv could not possibly have told it apart – short of doing some runtime-measurements on its own, which is only possible in the IO Monad.
⬜
You can look it up on wikipedia, it's called Reversible Computing.
In general you can't do it though and none of the functional languages have that option. For example:
f :: a -> Int
f _ = 1
This function does not have an inverse.
Not in most functional languages, but in logic programming or relational programming, most functions you define are in fact not functions but "relations", and these can be used in both directions. See for example prolog or kanren.
Tasks like this are almost always undecidable. You can have a solution for some specific functions, but not in general.
Here, you cannot even recognize which functions have an inverse. Quoting Barendregt, H. P. The Lambda Calculus: Its Syntax and Semantics. North Holland, Amsterdam (1984):
A set of lambda-terms is nontrivial if it is neither the empty nor the full set. If A and B are two nontrivial, disjoint sets of lambda-terms closed under (beta) equality, then A and B are recursively inseparable.
Let's take A to be the set of lambda terms that represent invertible functions and B the rest. Both are non-empty and closed under beta equality. So it's not possible to decide whether a function is invertible or not.
(This applies to the untyped lambda calculus. TBH I don't know if the argument can be directly adapted to a typed lambda calculus when we know the type of a function that we want to invert. But I'm pretty sure it will be similar.)
If you can enumerate the domain of the function and can compare elements of the range for equality, you can - in a rather straightforward way. By enumerate I mean having a list of all the elements available. I'll stick to Haskell, since I don't know Ocaml (or even how to capitalise it properly ;-)
What you want to do is run through the elements of the domain and see if they're equal to the element of the range you're trying to invert, and take the first one that works:
inv :: Eq b => [a] -> (a -> b) -> (b -> a)
inv domain f b = head [ a | a <- domain, f a == b ]
Since you've stated that f is a bijection, there's bound to be one and only one such element. The trick, of course, is to ensure that your enumeration of the domain actually reaches all the elements in a finite time. If you're trying to invert a bijection from Integer to Integer, using [0,1 ..] ++ [-1,-2 ..] won't work as you'll never get to the negative numbers. Concretely, inv ([0,1 ..] ++ [-1,-2 ..]) (+1) (-3) will never yield a value.
However, 0 : concatMap (\x -> [x,-x]) [1..] will work, as this runs through the integers in the following order [0,1,-1,2,-2,3,-3, and so on]. Indeed inv (0 : concatMap (\x -> [x,-x]) [1..]) (+1) (-3) promptly returns -4!
The Control.Monad.Omega package can help you run through lists of tuples etcetera in a good way; I'm sure there's more packages like that - but I don't know them.
Of course, this approach is rather low-brow and brute-force, not to mention ugly and inefficient! So I'll end with a few remarks on the last part of your question, on how to 'write' bijections. The type system of Haskell isn't up to proving that a function is a bijection - you really want something like Agda for that - but it is willing to trust you.
(Warning: untested code follows)
So can you define a datatype of Bijection s between types a and b:
data Bi a b = Bi {
apply :: a -> b,
invert :: b -> a
}
along with as many constants (where you can say 'I know they're bijections!') as you like, such as:
notBi :: Bi Bool Bool
notBi = Bi not not
add1Bi :: Bi Integer Integer
add1Bi = Bi (+1) (subtract 1)
and a couple of smart combinators, such as:
idBi :: Bi a a
idBi = Bi id id
invertBi :: Bi a b -> Bi b a
invertBi (Bi a i) = (Bi i a)
composeBi :: Bi a b -> Bi b c -> Bi a c
composeBi (Bi a1 i1) (Bi a2 i2) = Bi (a2 . a1) (i1 . i2)
mapBi :: Bi a b -> Bi [a] [b]
mapBi (Bi a i) = Bi (map a) (map i)
bruteForceBi :: Eq b => [a] -> (a -> b) -> Bi a b
bruteForceBi domain f = Bi f (inv domain f)
I think you could then do invert (mapBi add1Bi) [1,5,6] and get [0,4,5]. If you pick your combinators in a smart way, I think the number of times you'll have to write a Bi constant by hand could be quite limited.
After all, if you know a function is a bijection, you'll hopefully have a proof-sketch of that fact in your head, which the Curry-Howard isomorphism should be able to turn into a program :-)
I've recently been dealing with issues like this, and no, I'd say that (a) it's not difficult in many case, but (b) it's not efficient at all.
Basically, suppose you have f :: a -> b, and that f is indeed a bjiection. You can compute the inverse f' :: b -> a in a really dumb way:
import Data.List
-- | Class for types whose values are recursively enumerable.
class Enumerable a where
-- | Produce the list of all values of type #a#.
enumerate :: [a]
-- | Note, this is only guaranteed to terminate if #f# is a bijection!
invert :: (Enumerable a, Eq b) => (a -> b) -> b -> Maybe a
invert f b = find (\a -> f a == b) enumerate
If f is a bijection and enumerate truly produces all values of a, then you will eventually hit an a such that f a == b.
Types that have a Bounded and an Enum instance can be trivially made RecursivelyEnumerable. Pairs of Enumerable types can also be made Enumerable:
instance (Enumerable a, Enumerable b) => Enumerable (a, b) where
enumerate = crossWith (,) enumerate enumerate
crossWith :: (a -> b -> c) -> [a] -> [b] -> [c]
crossWith f _ [] = []
crossWith f [] _ = []
crossWith f (x0:xs) (y0:ys) =
f x0 y0 : interleave (map (f x0) ys)
(interleave (map (flip f y0) xs)
(crossWith f xs ys))
interleave :: [a] -> [a] -> [a]
interleave xs [] = xs
interleave [] ys = []
interleave (x:xs) ys = x : interleave ys xs
Same goes for disjunctions of Enumerable types:
instance (Enumerable a, Enumerable b) => Enumerable (Either a b) where
enumerate = enumerateEither enumerate enumerate
enumerateEither :: [a] -> [b] -> [Either a b]
enumerateEither [] ys = map Right ys
enumerateEither xs [] = map Left xs
enumerateEither (x:xs) (y:ys) = Left x : Right y : enumerateEither xs ys
The fact that we can do this both for (,) and Either probably means that we can do it for any algebraic data type.
Not every function has an inverse. If you limit the discussion to one-to-one functions, the ability to invert an arbitrary function grants the ability to crack any cryptosystem. We kind of have to hope this isn't feasible, even in theory!
In some cases, it is possible to find the inverse of a bijective function by converting it into a symbolic representation. Based on this example, I wrote this Haskell program to find inverses of some simple polynomial functions:
bijective_function x = x*2+1
main = do
print $ bijective_function 3
print $ inverse_function bijective_function (bijective_function 3)
data Expr = X | Const Double |
Plus Expr Expr | Subtract Expr Expr | Mult Expr Expr | Div Expr Expr |
Negate Expr | Inverse Expr |
Exp Expr | Log Expr | Sin Expr | Atanh Expr | Sinh Expr | Acosh Expr | Cosh Expr | Tan Expr | Cos Expr |Asinh Expr|Atan Expr|Acos Expr|Asin Expr|Abs Expr|Signum Expr|Integer
deriving (Show, Eq)
instance Num Expr where
(+) = Plus
(-) = Subtract
(*) = Mult
abs = Abs
signum = Signum
negate = Negate
fromInteger a = Const $ fromIntegral a
instance Fractional Expr where
recip = Inverse
fromRational a = Const $ realToFrac a
(/) = Div
instance Floating Expr where
pi = Const pi
exp = Exp
log = Log
sin = Sin
atanh = Atanh
sinh = Sinh
cosh = Cosh
acosh = Acosh
cos = Cos
tan = Tan
asin = Asin
acos = Acos
atan = Atan
asinh = Asinh
fromFunction f = f X
toFunction :: Expr -> (Double -> Double)
toFunction X = \x -> x
toFunction (Negate a) = \a -> (negate a)
toFunction (Const a) = const a
toFunction (Plus a b) = \x -> (toFunction a x) + (toFunction b x)
toFunction (Subtract a b) = \x -> (toFunction a x) - (toFunction b x)
toFunction (Mult a b) = \x -> (toFunction a x) * (toFunction b x)
toFunction (Div a b) = \x -> (toFunction a x) / (toFunction b x)
with_function func x = toFunction $ func $ fromFunction x
simplify X = X
simplify (Div (Const a) (Const b)) = Const (a/b)
simplify (Mult (Const a) (Const b)) | a == 0 || b == 0 = 0 | otherwise = Const (a*b)
simplify (Negate (Negate a)) = simplify a
simplify (Subtract a b) = simplify ( Plus (simplify a) (Negate (simplify b)) )
simplify (Div a b) | a == b = Const 1.0 | otherwise = simplify (Div (simplify a) (simplify b))
simplify (Mult a b) = simplify (Mult (simplify a) (simplify b))
simplify (Const a) = Const a
simplify (Plus (Const a) (Const b)) = Const (a+b)
simplify (Plus a (Const b)) = simplify (Plus (Const b) (simplify a))
simplify (Plus (Mult (Const a) X) (Mult (Const b) X)) = (simplify (Mult (Const (a+b)) X))
simplify (Plus (Const a) b) = simplify (Plus (simplify b) (Const a))
simplify (Plus X a) = simplify (Plus (Mult 1 X) (simplify a))
simplify (Plus a X) = simplify (Plus (Mult 1 X) (simplify a))
simplify (Plus a b) = (simplify (Plus (simplify a) (simplify b)))
simplify a = a
inverse X = X
inverse (Const a) = simplify (Const a)
inverse (Mult (Const a) (Const b)) = Const (a * b)
inverse (Mult (Const a) X) = (Div X (Const a))
inverse (Plus X (Const a)) = (Subtract X (Const a))
inverse (Negate x) = Negate (inverse x)
inverse a = inverse (simplify a)
inverse_function x = with_function inverse x
This example only works with arithmetic expressions, but it could probably be generalized to work with lists as well. There are also several implementations of computer algebra systems in Haskell that may be used to find the inverse of a bijective function.
No, not all functions even have inverses. For instance, what would the inverse of this function be?
f x = 1