HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Is there a universal identity or zero value for folding?

Submitted by: @import:stackexchange-cs··
0
Viewed 0 times
identityuniversalfoldingvaluefortherezero

Problem

I'm using Haskell notation for illustration, hopefully it is known widely enough for this to make sense.

In the following fold function the second argument is what I'm calling the identity:

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b


It is trivial to fold/reduce over a list of values with certain operations such as addition or multiplication. e.g.

mySum :: (Num a, Foldable t) => t a -> a
mySum = foldr (+) 0   --NB. Works because 0 is the additive identity

myProduct :: (Num a, Foldable t) => t a -> a
myProduct = foldr (*) 1  --NB. Works because 1 is the multiplicative identity


But not all operations have an obvious identity value.

My question is whether there is such thing as a universal identity value, or a function whereby you can find the identity value, or if you can contrive a scheme so that there now is one.

i.e. can you somehow define a z value such that:

foldrUniversal :: Foldable t => (a -> b -> b) -> t a -> b
foldrUniversal f = foldr f z


or could you have a function that determines it:

findIdentity :: (a -> b -> b) -> z  --is this possible?

foldrUniversal f = foldr f (findIdentity f)


or can you use some trick so that you always have an identity value even if you don't know what it should be?

(Note that I'm not stuck on a programming problem. I already know about foldr1 in Haskell, or using the head of the list as the identity and then the tail of the list as the list argument. I posted in cs.stackexchange instead of StackOverflow because I'm interested in the theoretical possibilities.)

Solution

Assume we can define

foldrUniversal :: Foldable t => (a -> b -> b) -> t a -> b


Then,

foo :: b
foo = foldrUniversal (\x y -> y) []


Is a way to form a value for any type b. If the type system is sane, this implies that foo does not terminate, as if we recursively defined foo = foo. Otherwise, all the types would be inhabited, making the logic associated to the type system to be inconsistent. A type system that allows this would be regarded as essentially "broken".

In real world languages, we do (grudgingly) allow some unwanted inhabitants. Non-terminating values ("bottom") are common ones, since they are mandatory in language with unconstrained recursion. null values are also used in many OOP based languages -- this is a so-called "billion dollar mistake", and should be avoided. Having a way to craft a "real" value of type b (say non-null, non-bottom) from nothing is too much.

Code Snippets

foldrUniversal :: Foldable t => (a -> b -> b) -> t a -> b
foo :: b
foo = foldrUniversal (\x y -> y) []

Context

StackExchange Computer Science Q#81918, answer score: 5

Revisions (0)

No revisions yet.