Is ((f f) (g g)) reduced differently in AOR and NOR? - functional-programming

How is ((f f) (g g)) reduced in both applicative order reduction and normal order reduction? do both reduce the statement in the same way?

Assume "reduce" means "Beta-Reduct".
I'm not going to be rigorous and introduice formals definitions, because of this is not the question.
Before, i need to clarify some terms :
A beta-contraction (writes ~> here) means a single step of the evaluation.
For example (λx.λy.xy)(a)(b) ~> (λy.ay)(b) forall terms a, b
A beta-reduction (writes => here) means a complete evaluation.
For example (λx.λy.xy)(a)(b) => ab forall atoms a, b
A term is in a beta-normal form if it's no contain redexes.
For example λx.x is a beta-normal form, but (λx.x)y has a beta-normal form (y) iff y has a beta-normal form.
An other important point : A term A has a unique beta-normal form regardless wich strategy we apply to reduce A.
Two terms are beta-equals (writes == here) if their beta-normal forms are alpha-equivalent
For example (λx.λy.xy)(a)(b) == (λy.ay)(b)
In the case of the AOR strategy, to reduce a term A, we beta-contract the rightmost innermost redex until we get a beta-normal form.
More visually :
>> (λx.x)((λy.y)((λz.z)a))
~> (λx.x)((λy.y)a)
~> (λx.x)a
~> a
In the case of the NOR strategy, to reduce a term A, we beta-contract the leftmost outermost redex until we get a beta-normal form
More visually :
>> (λx.x)((λy.y)((λz.z)a))
~> (λy.y)((λz.z)a)
~> (λz.z)a
~> a
So, in your case, with f f => A, g g => B
AOR :
>> (f f)(g g)
~> (f f)B
~> AB
NOR :
>> (f f)(g g)
~> A(g g)
~> AB
It's not very rigorous, but the idea is clear.
And, of course, (f f)(g g) == (f f)(g g)

Related

How do I write Functor and Applicative for Vector-Composition?

I´m trying to learn more about dependent types using IDRIS.
The example I am trying to emulate uses composition of Vectors.
I understand Functor and Applicative implementations for Vectors but I am struggling to implement them for the Composition.
data Vector : Nat -> Type -> Type where
Nil : Vector Z a
(::) : a -> Vector n a -> Vector (S n) a
Functor (Vector n) where
map f [] = []
map f (x::xs) = f x :: map f xs
Applicative (Vector n) where
pure = replicate _
fs <*> vs = zipWith apply fs vs
Now the Composition and Decomposition-Function look like this:
data (:++) : (b -> c) -> (a -> b) -> a -> Type where
Comp : (f . g) x -> (f :++ g) x
unComp : (f :++ g) a -> (f . g) a
unComp (Comp a) = a
User with Vectors it encapsulates a Vector of Vectors.
Now I need an Applicative for the Composition (Vector n) :++ (Vector n).
I can´t even get Functor to work and am mainly trying to see what I´m doing wrong. I tried the following and, since Functor is already implemented for Vectors, that this would work
Functor ((Vector n) :++ (Vector n)) where
map f (Comp []) = Comp []
map f (Comp (x::xs)) = Comp ((f x) :: (map f (Comp xs)))
but the Compiler gives an Error-Message:
When checking an application of constructor Main.:::
Unifying a and Vector (S n) a would lead to infinite value
Isn´t unifying and element of type a and a Vector n a exactly the purpose of (::)?
I am obviously doing something wrong and I can´t get this to work. I also have the feeling it´s probably easy to solve, but after hours of reading and trying I still don´t get it.
If someone could give me advice or explain to me how the Functor and Applicative implementations could look like, I would be very grateful.
Update: Idris 2 now has this builtin. Functor for Compose, Applicative for Compose
I think you can implement a general instance of Functor and Applicative like with Haskell's Compose.
newtype Compose f g a = Compose { getCompose :: f (g a) }
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose x) = Compose (fmap (fmap f) x)
a <$ (Compose x) = Compose (fmap (a <$) x)
instance (Applicative f, Applicative g) => Applicative (Compose f g) where
pure x = Compose (pure (pure x))
Compose f <*> Compose x = Compose (liftA2 (<*>) f x)
liftA2 f (Compose x) (Compose y) =
Compose (liftA2 (liftA2 f) x y)
To answer your specific question (but don't do it this way):
Functor ((Vector n) :++ (Vector n)) where
map f (Comp x) = Comp $ map (map f) x

Recursion in the calculus of construction

How to define a recursive function in the (pure) calculus of constructions? I do not see any fixpoint combinator there.
People in the CS stack exchange might be able to provide some more insight, but here is an attempt.
Inductive data types are defined in the calculus of constructions with a Church encoding: the data type is the type of its fold function. The most basic example are the natural numbers, which are defined as follows, using a Coq-like notation:
nat := forall (T : Type), T -> (T -> T) -> T
This encoding yields two things: (1) terms zero : nat and succ : nat -> nat for constructing natural numbers, and (2) an operator nat_rec for writing recursive functions.
zero : nat
zero T x f := x
succ : nat -> nat
succ n T x f := f (n T x f)
nat_rec : forall T, T -> (T -> T) -> nat -> T
nat_rec T x f n := n T x f
If we pose F := nat_rec T x f for terms x : T and f : T -> T, we see that the following equations are valid:
F zero = x
F (succ n) = f (F n)
Thus, nat_rec allows us to define recursive functions by specifying a return value x for the base case, and a function f to process the value of the recursive call. Note that this does not allow us to define arbitrary recursive functions on the natural numbers, but only those that perform recursive calls on the predecessor of their argument. Allowing arbitrary recursion would open the door to partial functions, which would compromise the soundness of the calculus.
This example can be generalized to other inductive data types. For instance, we can define the type of lists of natural numbers as the type of their fold right function:
list_nat := forall T, T -> (nat -> T -> T) -> T

Confusion in understanding Substitution / `ap` type signature and different implementations (functional programming)

I am a student of functional programming, sorry if my question sounds weird--I am trying to wrap my mind around the given type signatures for functions and how they are implemented.
Looking at the signature for ap (Substitution)
https://gist.github.com/Avaq/1f0636ec5c8d6aed2e45
(a → b → c) → (a → b) → a → c
Is given here as
const S = f => g => x => f(x)(g(x));
Which I think I understand. f is a function that takes two parameters, a and b and returns c. g is a function that takes a and returns b. So g(a) returns b and therefore f(a)(b) can be written as f(a)(g(a)), which returns c.
g(a) is the substitute for b ?
Ok now I'm looking at a different implementation that still makes sense:
https://github.com/sanctuary-js/sanctuary-type-classes/tree/v7.1.1#ap--applyf--fa-bfa---fb
ap(Identity(Math.sqrt), Identity(64))
The type signature
(f (a -> b), f a) -> f b
Seem similar to
(a → b → c) → (a → b) → a → c
Re-writing the second using a = f, b = a, and c = b I get
(f -> a -> b) -> (f -> a) -> f -> b
Presuming that ap takes two parameters, where in the first f could be some functor that contains a function a -> b and in the second f some functor that contains a returning a functor that substitutes the first functor's function with the end point b given then functor containing a.
Okay, stepping back, these two things looks vastly different and I can't wrap my mind around how they are somehow saying the same thing.
const S = f => g => x => f(x)(g(x))
ap(Identity(Math.sqrt), Identity(64))
From my understanding, ap(F(g),F(a)) can be express as F(a).map(g) which, again, I still have a hard time equating to const S = f => g => x => f(x)(g(x)). Perhaps I'm misunderstanding something.
...maybe my misunderstanding has to do with the expression of ap and how that correlates to f => g => x => f(x)(g(x)) because I can see how they both express the same signature but I don't see them as the same thing.
Anyone who can lend some cognitive assistance here, I would greatly appreciate it
ap is the name for a transformation that behaves the same way on a large number of container types known as Applicative Functors. One such container type is the Function: it can be treated as a container of its return value.
The S combinator you found in my gist comes from the untyped Lambda Calculus and is a transformation of a Function specifically. It happens to also be a valid implementation of Applicative Functor for Function, and it happens to be the implementation of choice for both Ramda and Sanctuary. This is why you can use ap as S.
To gain an understanding of how ap is S, let's have a look at the signature for ap:
Apply f => (f (a -> b), f a) -> f b
And let's get rid of the comma by currying the function. This should make the next steps a little easier to follow:
Apply f => f (a -> b) -> f a -> f b
The Apply f part shows that, where ever we see f a, we can use an Applicative Functor container that contains a. Let's specialise this signature for the Function container, by replacing f with (Function x). x is the input to the function, and what follows is the output.
(Function x) (a -> b) -> (Function x) a -> (Function x) b
This reads as: Given a Function from x to a Function from a to b, and a Function from x to a, returns a Function from x to b.
We can remove the brackets around Function x, because of the way constructor associativity works:
Function x (a -> b) -> Function x a -> Function x b
And another way to write Function a b is using the arrow notation: (a -> b), so in the next step we do just that:
(x -> (a -> b)) -> (x -> a) -> (x -> b)
And finally we can get rid of the additional brackets again, and find that it's our S combinator:
(x -> a -> b) -> (x -> a) -> x -> b
(a -> b -> c) -> (a -> b) -> a -> c
First of all, I think there is no easy explanation of why the applicative functor for the function type in untyped lambda calculus is called substitution. AFAIK, Schönfinkel originally called this combinator fusing or amalgamation function.
In order to specialize the general applicative functor type (f (a -> b), f a) -> f b (uncurried form), we need to know what the parameterized type variable f exactly represents in the context of the function type.
As every functor applicative functors are parameterized over a single type. The function type constructor, however, needs two types - one for the argument and another for the return value. For functions to be an instance of (applicative) functors, we must therefore ignore the type of the return value. Consequently, f represents (a -> ), ie. the function type itself and the type of its argument. The correct notation for the partially applied function type constructor is actually prefix (->) a, so let's stick to this.
Next, I'm gonna rewrite the general applicative type in curried form and substitute f with (->) r. I use another letter to delimit the type parameter of the applicative from other type variables:
(f (a -> b), f a) -> f b
f (a -> b) -> f a -> f b // curried form
// substitution
(->) r (a -> b) -> (->) r a -> (->) r b // prefix notation
(r -> a -> b) -> (r -> a) -> (r -> b) // infix notation
// omit unnecessary parenthesis
(r -> a -> b) -> (r -> a) -> r -> b
This is exactly the type of the S combinator.

coq --- function power definition

I am interested in how would one define f to the n in Coq:
Basically, as an exercise, I would like to write this definition and then confirm that my
algorithm implements this specification. Inductive definition seems appropriate here, but I was not able to make it clean as above. What would be a clean Coq implementation of the above?
With the pow_func function that gallais defined, you can state your specification as lemmas, such as:
Lemma pow_func0: forall (A:Type) (f: A -> A) (x: A), pow_fun f O x = f x.
and
Lemma pow_funcS: forall (n:nat) (A: Type) (f: A->A) (x:A), pow_fun f (S n) x = f (pow_fun f n x).
The proof should be trivial by unfolding the definition
Inductive is used to define types closed under some operations; this is not what you are looking for here. What you want to build is a recursive function iterating over n. This can be done using the Fixpoint keyword:
Fixpoint pow_func {A : Type} (f : A -> A) (n : nat) (a : A) : A :=
match n with
| O => f a
| S n => f (pow_func f n a)
end.
If you want a nicer syntax for this function, you can introduce a Notation:
Notation "f ^ n" := (pow_func f n).
However, note that this is not a well-behaved definition of a notion of power: if you compose f ^ m and f ^ n, you don't get f ^ (m + n) but rather f ^ (1 + m + n). To fix that, you should pick the base case f ^ 0 to be the neutral element for composition id rather than f itself. Which would give you:
Fixpoint pow_func' {A : Type} (f : A -> A) (n : nat) (a : A) : A :=
match n with
| O => a
| S n => f (pow_func' f n a)
end.

In pure functional languages, is there an algorithm to get the inverse function?

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

Resources