Functional Programming à la 1940s: Minimalistic Implementation of Factorial - haskell

I have watched the amazing talk by John Hughes titled Why Functional Programming Matters a couple of times and only recently decided to actually try implementing the "minimalist" version of booleans, integers, and of course factorial, as shown in the video.
I implemented true, false, ifte, zero, one, two, iszero, decr and finally fact here as follow:
-- boolean
true x y = x
false x y = y
ifte bool t e = bool t e
-- positive integers
three f x = f $ f $ f x
two f x = f $ f x
one f x = f x
zero f x = x
-- add and multiplication
add m n f x = m f $ n f x
mul m n f x = m (n f) x
-- is zero check
iszero n = n (\_ -> false) true
-- decrement
decr n =
n (\m f x -> f (m f zero))
zero
(\x->x)
zero
-- factorial
fact n =
ifte (iszero n)
one
(mul n (fact (decr n)))
Problem
I tested every function, and they all compile and work perfectly, except for decr and fact.
Even though John Hughes promises at 6:37 that his implementation of decr works, it fails to compile with the following error:
error: Variable not in scope: incr
I am not certain how incr should be implemented in (\m f x -> f (m incr zero)).
Now if I define them as incr = (+1) and change the definition of decr to the following, then decr compiles and works fine, but fact still causes compilation failure.
decr n =
n (\m f x -> f (m incr x))
zero
(\x->x)
zero'
Is there a bug in the lambda (\m f x -> f (m incr zero)) used in the definition of decr, or should incr be defined differently?
Update
When I define incr as incr n = (\f x -> f (n f x)), decr n works fine, but fact n fails to compile. Here's the readable portion of the error message:
factorial.hs:30:1: error:
• Occurs check: cannot construct the infinite type:
...
| fact n =
| ^^^^^^^^...
...
factorial.hs:33:6: error:
• Occurs check: cannot construct the infinite type:
...
• In the third argument of ‘ifte’, namely ‘(mul n (fact (decr n)))’
In the expression: ifte (iszero n) one (mul n (fact (decr n)))
In an equation for ‘fact’:
fact n = ifte (iszero n) one (mul n (fact (decr n)))
...
| (mul n (fact (decr n)))
| ^^^^^^^^^^^^^^^^^^^^^
Note: the complete error message is several pages long.

It looks like you're really close
I can show you how to do this using Church's encodings in JavaScript, but not in Haskell, because I don't know how to make some simple combinators type-check in Haskell (U below)
Because JavaScript is strictly evaluated, predicate branches must be wrapped in a lambda
Go ahead and run the snippet – we calculate 8!
const True = a => b =>
a ()
const False = a => b =>
b ()
const IsZero = n =>
n (x => False) (True)
const Succ = n =>
f => x => f (n (f) (x))
const Pred = n =>
f => x => n (g => h => h (g (f))) (u => x) (u => u)
const Mult = m => n =>
f => m (n (f))
const Add = m => n =>
m (Succ) (n)
const one = f => x =>
f (x)
const two =
Add (one) (one)
const four =
Add (two) (two)
const eight =
Add (four) (four)
const U = f => f (f)
const Fact = U (f => acc => n =>
IsZero (n)
(z => acc) // thunks used for predicate branches
(z => U (f) (Mult (acc) (n)) (Pred (n)))) (one)
const result =
Fact (eight)
// convert church numeral result to a JavaScript number
console.log ('8! =', result (x => x + 1) (0))
// 8! = 40320
If you cheat a little, you can achieve faux laziness by using JavaScript's ?: ternary operator – I'm only showing this so you can see Fact in a more readable form; the above implementation uses only lambdas
const IsZero = n =>
// cheat by returning JavaScript's true/false booleans
n (x => false) (true)
const Succ = n =>
f => x => f (n (f) (x))
const Pred = n =>
f => x => n (g => h => h (g (f))) (u => x) (u => u)
const Mult = m => n =>
f => m (n (f))
const Add = m => n =>
m (Succ) (n)
const one = f => x =>
f (x)
const two =
Add (one) (one)
const four =
Add (two) (two)
const eight =
Add (four) (four)
const U = f => f (f)
const Fact = U (f => acc => n =>
IsZero (n)
? acc // now we're sorta cheating using JavaScript's ternary here
: U (f) (Mult (acc) (n)) (Pred (n))) (one)
const result =
Fact (eight)
console.log ('8! =', result (x => x + 1) (0))
// 8! = 40320

First, let's try to explicitly type everything. Naïvely, all this stuff is parameterised on some type that the Church functions deal with:
type Logical a = a -> a -> a
type Nat a = (a->a) -> a->a
-- boolean
true, false :: Logical a
true x y = x
false x y = y
ifte :: Logical a -> a -> a -> a
ifte = id
incr :: Nat a -> Nat a
incr n f = f . n f
-- integer “literals”
zero, one, two, three :: Nat a
three = incr two
two = incr one
one = incr zero
zero _ = id
-- addition and multiplication
add, mul :: Nat a -> Nat a -> Nat a
add m n f = m f . n f
mul m n f = m $ n f
-- zero check
isZero :: Nat a -> Logical a
isZero n = n (const false) true
...ok, here we run into the first problem:
• Couldn't match expected type ‘Logical a’ with actual type ‘a’
‘a’ is a rigid type variable bound by
the type signature for:
isZero :: forall a. Nat a -> Logical a
at /tmp/wtmpf-file7834.hs:25:1-28
• In the expression: n (const false) true
The issue is that we try to use the Nat-church-numbers as a function not on the underlying a type that the result Logical is supposed to work with, but on those logicals themselves. I.e. it's actually
isZero :: Nat (Logical a) -> Logical a
It gets worse for decr – this doesn't work:
decr :: Nat a -> Nat a
decr n = n (\m f x -> f (m incr x))
zero
id
zero
because you're trying to use the number for both a logical purpose as in isZero, which requires injecting another Nat layer, but also for just passing on/incrementing. In traditional Hindley-Milner, you'd need to decide on one of these, so it's not possible to make it typecheck.
In modern Haskell, you can make it typecheck, by making the argument polymorphic:
{-# LANGUAGE RankNTypes, UnicodeSyntax #-}
decr :: (∀ α . Nat α) -> Nat a
To avoid carrying around the quantifier, we might make another synonym:
type ANat = ∀ α . Nat α
then it's just
decr :: ANat -> Nat a
And that technique works for the factorial as well:
fact :: ANat -> Nat a
fact n = ifte (isZero n)
one
(mul n $ fact (decr n))

Related

Fold that's both constant-space and short-circuiting

I'm trying to build a Haskell function that does basically the same thing as Prelude's product. Unlike that function, however, it should have these two properties:
It should operate in constant space (ignoring the fact that some numeric types like Integer aren't). For example, I want myProduct (replicate 100000000 1) to eventually return 1, unlike Prelude's product which uses up all of my RAM and then gives *** Exception: stack overflow.
It should short-circuit when it encounters a 0. For example, I want myProduct (0:undefined) to return 0, unlike Prelude's product which gives *** Exception: Prelude.undefined.
Here's what I've come up with so far:
myProduct :: (Eq n, Num n) => [n] -> n
myProduct = go 1
where go acc (x:xs) = if x == 0 then 0 else acc `seq` go (acc * x) xs
go acc [] = acc
That works exactly how I want it to for lists, but I'd like to generalize it to have type (Foldable t, Eq n, Num n) => t n -> n. Is it possible to do this with any of the folds? If I just use foldr, then it will short-circuit but won't be constant-space, and if I just use foldl', then it will be constant-space but won't short-circuit.
If you spell your function slightly differently, it's more obvious how to turn it into a foldr. Namely:
myProduct :: (Eq n, Num n) => [n] -> n
myProduct = flip go 1 where
go (x:xs) = if x == 0 then \acc -> 0 else \acc -> acc `seq` go xs (acc * x)
go [] = \acc -> acc
Now go has got that foldr flavor, and we can just fill in the holes.
myProduct :: (Foldable t, Eq n, Num n) => t n -> n
myProduct = flip go 1 where
go = foldr
(\x f -> if x == 0 then \acc -> 0 else \acc -> acc `seq` f (acc * x))
(\acc -> acc)
Hopefully you can see where each of those pieces came from in the previous explicit-recursion style and how mechanical the transformation is. Then I'd make a few aesthetic tweaks:
myProduct :: (Foldable t, Eq n, Num n) => t n -> n
myProduct xs = foldr step id xs 1 where
step 0 f acc = 0
step x f acc = f $! acc * x
And we're all done! A bit of quick testing in ghci reveals that it still short-circuits on 0 as required and uses constant space when specialized to lists.
You might be looking for foldM. Instantiate it with m = Either b and you get short circuiting behavior (or Maybe, depends if you have many possible early exit values, or one known in advance).
foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
I recall discussions whether there should be foldM', but IIRC GHC does the right thing most of the time.
import Control.Monad
import Data.Maybe
myProduct :: (Foldable t, Eq n, Num n) => t n -> n
myProduct = fromMaybe 0 . foldM go 1
where go acc x = if x == 0 then Nothing else Just $! acc * x

Find tree height using folde function in Haskell

One of the assignments I am working on leading up to exams had me create
data Exp = T | F | And Exp Exp | Or Exp Exp | Not Exp deriving (Eq, Show, Ord, Read)
Then it asked to make
folde :: a -> a -> (a -> a -> a) -> (a -> a -> a) -> (a -> a) -> Exp -> a
This is what I came up with
folde :: a -> a -> (a -> a -> a) -> (a -> a -> a) -> (a -> a) -> Exp -> a
folde t f a o n T = t
folde t f a o n F = f
folde t f a o n (And x y) = a (folde t f a o n x) (folde t f a o n y)
folde t f a o n (Or x y) = o (folde t f a o n x) (folde t f a o n y)
folde t f a o n (Not x) = n (folde t f a o n x)
The assignment asks for evb, evi and evh.
They are all supposed to work with one single call to folde using correct parameters.
Evb evaluates boolean expressions.
evb :: Exp -> Bool
evb = folde True False (&&) (||) not
Evi evaluates to an integer, treating T as Int 1, F as Int 5, And as +, Or as * and Not as negate.
evi :: Exp -> Int
evi = folde 1 5 (+) (*) negate
So far so good, it all works. I'll be happy for any feedback on this as well.
However, I can't seem to understand how to solve the evh.
evh is supposed to calculate the heigh of the tree.
It should be evh :: Exp -> Int
The assignment says it should treat T and F as height 1.
It goes on that Not x should evaluate to height x + 1. And and Or has the height of its tallest subtree + 1.
I can't seem to figure out what I should pass on to my folde function
The assignment says it should treat T and F as height 1. It goes on that Not x should evaluate to height x + 1. And and Or has the height of its tallest subtree + 1.
You can write this pretty directly with explicit recursion:
height T = 1
height F = 1
height (Not x) = height x + 1
height (And x y) = max (height x) (height y) + 1
height (Or x y) = max (height x) (height y) + 1
Now, how do you write this with folde? The key thing about recursive folding is that folde gives each of your functions the result of folding all the subtrees. When you folde on And l r, it folds both subtrees first, and then passes those results into the argument to folde. So, instead of you manually calling height x, folde is going to calculate that for you and pass it as an argument, so your own work ends up something like \x y -> max x y + 1. Essentially, split height into 5 definitions, one per constructor, and instead of destructuring and recursing down subtrees, take the heights of the subtrees as arguments:
heightT = 1 -- height T = 1
heightF = 1 -- height F = 1
heightN x = x + 1 -- height (Not x) = height x + 1
heightA l r = max l r + 1 -- height (And l r) = max (height l) (height r) + 1
heightO l r = max l r + 1 -- height (Or l r) = max (height l) (height r) + 1
Feed them to folde, and simplify
height = folde 1 1 -- T F
ao -- And
ao -- Or
(+1) -- Not
where ao x y = max x y + 1
And now for something new! Take this definition:
data ExpF a = T | F | Not a | And a a | Or a a
deriving (Functor, Foldable, Traversable)
This looks like your Exp, except instead of recursion it's got a type parameter and a bunch of holes for values of that type. Now, take a look at the types of expressions under ExpF:
T :: forall a. ExpF a
Not F :: forall a. ExpF (ExpF a)
And F (Not T) :: forall a. ExpF (ExpF (ExpF a))
If you set a = ExpF (ExpF (ExpF (ExpF (ExpF ...)))) (on to infinity) in each of the above, you find that they can all be made to have the same type:
T :: ExpF (ExpF (ExpF ...))
Not F :: ExpF (ExpF (ExpF ...))
And F (Not T) :: ExpF (ExpF (ExpF ...))
Infinity is fun! We can encode this infinitely recursive type with Fix
newtype Fix f = Fix { unFix :: f (Fix f) }
-- Compare
-- Type level: Fix f = f (Fix f)
-- Value level: fix f = f (fix f)
-- Fix ExpF = ExpF (ExpF (ExpF ...))
-- fix (1:) = 1:( 1:( 1: ...))
-- Recover original Exp
type Exp = Fix ExpF
-- Sprinkle Fix everywhere to make it work
Fix T :: Exp
Fix $ And (Fix T) (Fix $ Not $ Fix F) :: Exp
-- can also use pattern synonyms
pattern T' = Fix T
pattern F' = Fix F
pattern Not' t = Fix (Not t)
pattern And' l r = Fix (And l r)
pattern Or' l r = Fix (Or l r)
T' :: Exp
And' T' (Not' F') :: Exp
And now here's the nice part: one definition of fold to rule them all:
fold :: Functor f => (f a -> a) -> Fix f -> a
fold alg (Fix ffix) = alg $ fold alg <$> ffix
-- ffix :: f (Fix f)
-- fold alg :: Fix f -> a
-- fold alg <$> ffix :: f a
-- ^ Hey, remember when I said folds fold the subtrees first?
-- Here you can see it very literally
Here's a monomorphic height
height = fold $ \case -- LambdaCase extension: \case ... ~=> \fresh -> case fresh of ...
T -> 1
F -> 1
Not x -> x + 1
And x y -> max x y + 1
Or x y -> max x y + 1
And now a very polymorphic height (in your case it's off by one; oh well).
height = fold $ option 0 (+1) . fmap getMax . foldMap (Option . Just . Max)
height $ Fix T -- 0
height $ Fix $ And (Fix T) (Fix $ Not $ Fix F) -- 2
See the recursion-schemes package to learn these dark arts. It also makes this work for base types like [] with a type family, and removes the need to Fix everything with said trickery + some TH.

Memoisation with auxiliary parameter in Haskell

I have a recursive function f that takes two parameters x and y. The function is uniquely determined by the first parameter; the second one merely makes things easier.
I now want to memoise that function w.r.t. it's first parameter while ignoring the second one. (I.e. f is evaluated at most one for every value of x)
What is the easiest way to do that? At the moment, I simply define an array containing all values recursively, but that is a somewhat ad-hoc solution. I would prefer some kind of memoisation combinator that I can just throw at my function.
EDIT: to clarify, the function f takes a pair of integers and a list. The first integer is some parameter value, the second one denotes the index of an element in some global list xs to consume.
To avoid indexing the list, I pass the partially consumed list to f as well, but obviously, the invariant is that if the first parameter is (m, n), the second one will always be drop n xs, so the result is uniquely determined by the first parameter.
Just using a memoisation combinator on the partially applied function will not work, since that will leave an unevaluated thunk \xs -> … lying around. I could probably wrap the two parameters in a datatype whose Eq instance ignores the second value (and similarly for other instances), but that seems like a very ad-hoc solution. Is there not an easier way?
EDIT2: The concrete function I want to memoise:
g :: [(Int, Int)] -> Int -> Int
g xs n = f 0 n
where f :: Int -> Int -> Int
f _ 0 = 0
f m n
| m == length xs = 0
| w > n = f (m + 1) n
| otherwise = maximum [f (m + 1) n, v + f (m + 1) (n - w)]
where (w, v) = xs !! m
To avoid the expensive indexing operation, I instead pass the partially-consumed list to f as well:
g' :: [(Int, Int)] -> Int -> Int
g' xs n = f xs 0 n
where f :: [(Int, Int)] -> Int -> Int -> Int
f [] _ _ = 0
f _ _ 0 = 0
f ((w,v) : xs) m n
| w > n = f xs (m + 1) n
| otherwise = maximum [f xs (m + 1) n, v + f xs (m + 1) (n - w)]
Memoisation of f w.r.t. the list parameter is, of course, unnecessary, since the list does not (morally) influence the result. I would therefore like the memoisation to simply ignore the list parameter.
Your function is unnecessarily complicated. You don't need the index m at all:
foo :: [(Int, Int)] -> Int -> Int
foo [] _ = 0
foo _ 0 = 0
foo ((w,v):xs) n
| w > n = foo xs n
| otherwise = foo xs n `max` foo xs (n - w) + v
Now if you want to memoize foo then both the arguments must be considered (as it should be).
We'll use the monadic memoization mixin method to memoize foo:
First, we create an uncurried version of foo (because we want to memoize both arguments):
foo' :: ([(Int, Int)], Int) -> Int
foo' ([], _) = 0
foo' (_, 0) = 0
foo' ((w,v):xs, n)
| w > n = foo' (xs, n)
| otherwise = foo' (xs, n) `max` foo' (xs, n - w) + v
Next, we monadify the function foo' (because we want to thread a memo table in the function):
foo' :: Monad m => ([(Int, Int)], Int) -> m Int
foo' ([], _) = return 0
foo' (_, 0) = return 0
foo' ((w,v):xs, n)
| w > n = foo' (xs, n)
| otherwise = do
a <- foo' (xs, n)
b <- foo' (xs, n - w)
return (a `max` b + v)
Then, we open the self-reference in foo' (because we want to call the memoized function):
type Endo a = a -> a
foo' :: Monad m => Endo (([(Int, Int)], Int) -> Int)
foo' _ ([], _) = return 0
foo' _ (_, 0) = return 0
foo' self ((w,v):xs, n)
| w > n = foo' (xs, n)
| otherwise = do
a <- self (xs, n)
b <- self (xs, n - w)
return (a `max` b + v)
We'll use the following memoization mixin to memoize our function foo':
type Dict a b m = (a -> m (Maybe b), a -> b -> m ())
memo :: Monad m => Dict a b m -> Endo (a -> m b)
memo (check, store) super a = do
b <- check a
case b of
Just b -> return b
Nothing -> do
b <- super a
store a b
return b
Our dictionary (memo table) will use the State monad and a Map data structure:
import Prelude hiding (lookup)
import Control.Monad.State
import Data.Map.Strict
mapDict :: Ord a => Dict a b (State (Map a b))
mapDict = (check, store) where
check a = gets (lookup a)
store a b = modify (insert a b)
Finally, we combine everything to create a memoized function memoFoo:
import Data.Function (fix)
type MapMemoized a b = a -> State (Map a b) b
memoFoo :: MapMemoized ([(Int, Int)], Int) Int
memoFoo = fix (memo mapDict . foo')
We can recover the original function foo as follows:
foo :: [(Int, Int)] -> Int -> Int
foo xs n = evalState (memoFoo (xs, n)) empty
Hope that helps.

Implementing Collatz Function

Learn You a Haskell mentions the Collatz Sequences:
We take a natural number. If that number is even, we divide it by two.
If it's odd, we multiply it by 3 and then add 1 to that.
When I tried to implement it, I ran into a problem
collatz :: (Integral a) => a -> [a]
collatz x
| odd x = f x : collatz (f x)
| otherwise = g x : collatz (g x)
where f y = y*3 + 1
g y = y/2
But I get this compile-time error:
CollatzSeq.hs:10:16:
Could not deduce (Fractional a) arising from a use of `g'
from the context (Integral a)
bound by the type signature for collatz :: Integral a => a -> [a]
at CollatzSeq.hs:7:12-35
Possible fix:
add (Fractional a) to the context of
the type signature for collatz :: Integral a => a -> [a]
In the first argument of `(:)', namely `g x'
In the expression: g x : collatz (g x)
In an equation for `collatz':
collatz x
| odd' x = f x : collatz (f x)
| otherwise = g x : collatz (g x)
where
f y = y * 3 + 1
g y = y / 2
As I understand, the problem is that calling collatz (g x) can return a Fractional since y / 2 returns a Double:
Prelude> let x = 4 / 2
Prelude> :t x
x :: Double
I tried to fix this type error by adding floor in front of the y/2, but that didn't work.
Please tell me how to fix this error.
Use div instead of (/). Alternately, if you want another rounding strategy than floor, you may use fromIntegral, as in
round (fromIntegral y / 2)
The error comes from the way / is defined. GHCI shows this result for :t (/):
(/) :: Fractional a => a -> a -> a
An alternative would be to use div, which has the type signature:
div :: Integral a => a -> a -> a
Secondly, you are skipping the input term in your current implementation. That should not be the case.
Finally, you need to add the base case for input = 1, otherwise your function will get caught in an infinite loop. You may change it to:
collatz :: (Integral a) => a -> [a]
collatz 1 = [1]
collatz x
| odd x = x : collatz (f x)
| otherwise = x : collatz (g x)
where f y = y*3 + 1
g y = y `div` 2

Recognizing haskell types

I'm having some difficulties in understanding the types in haskell. Let's consider the following functions and look at their types.
reduce f s [] = s
reduce f s (x:xs) = f x (reduce f s xs)
for m n f s = if m>n then s else for (m+1) n f ( f m s )
comp f g x y = f x (g x y)
iter 0 f s = s
iter n f s = iter (n-1) f (f s)
We'd have something like:
reduce :: (t1 -> t -> t) -> t -> [t1] -> t
for :: (Ord a, Num a) => a -> a -> (a -> t -> t) -> t -> t
comp :: (t -> t2 -> t3) -> (t -> t1 -> t2) -> t -> t1 -> t3
iter :: (Num t) => t -> (t1 -> t1) -> t1 -> t1
What I don't clearly understand is that in reduce function f takes two parameters, and in for function f again takes two parameters. All I can see is that it takes only one. Well if it would be something like that:
for m n f s = if m>n then s else for (m+1) n f m n
It would be more obvious and easy to recognize that f indeed takes two parameters.
I'm wondering if there exist some ways or method to deduce the types for functions in haskell. In addition to these examples I'd ask for some different examples, so that I can overcome that hardship.
EDIT: In my case function definitions are given, I am just trying to infer their types
Where you're making a thought mistake is in even considering f ( f m s ). That is not a subexpression of the for definition: recall that function application is parsed from the left. So
for (m+1) n f ( f m s )
≡ (for (m+1)) n f ( f m s )
≡ (for (m+1) n) f ( f m s )
≡ (for (m+1) n f) ( f m s )
≇ (for (m+1) n ) (f ( f m s ))
≇ for (m+1) (n f ( f m s ))
≇ for ((m+1) n f ( f m s ))
The last inequality is probably most obvious, because you'd be applying the function (m+1) to three arguments... that sure looks very unlikely.
If you need any "mental parenthesising" for understanding the function, it's normally best to put them around each function argument:
for (m+1) n f ( f m s )
≡ for (m+1)
(n)
(f)
(f m s)
and, if that helps you because it looks more like what you'd have in mainstream languages, you can also uncurry everything:
≅ for ( m+1, n, f, f(m,s) )
(though you'd better forget about that one quickly)
By the way: if you see a function applied to only one argument, it doesn't mean the function type has only one argument. In fact, the main strength of Haskell's curried syntax is that you can easily do partial application: e.g.
Prelude> :t take
take :: Int -> [a] -> [a]
Prelude> :t take 3
take 3 :: [a] -> [a]
Prelude> map (take 3) ["looooong", "even loonger", "terribly long"]
["loo","eve","ter"]
You see I've only applied take to one argument, the other one is automatically taken from the list by map.
Another example, with operator sections,
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> :t (+ 1)
(+ 1) :: Num a => a -> a
Prelude> map (+ 1) [4,5,6]
[5,6,7]
The type of f in the following definition is quite easy to infer
for m n f s = if m>n then s else for (m+1) n f ( f m s )
This could be rewritten (for clearity) as
for m n f s
| m>n = s
| otherwise = for (m+1) n f ( f m s )
for (m+1) n f (f m s) is a call of for,
which means f m s needs has the same type as s,
this requires f to have type t1 -> t -> t
(t1 for m, and t for s)

Resources