Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing the ordinals in Haskell

Tags:

haskell

I've begun learning Haskell, and I thought I would implement the ordinal numbers, using the common ("von Neumann") definition. So I wrote:

ordinal 0 = []
ordinal x = [ ordinal n | n<-[1..(x-1)] ]

But the interpreter was not satisfied, and it told me instead that supposedly

    * Couldn't match type `a' with `[a]'
Expected: t -> a
Actual: t -> [a]
* Relevant bindings include
ordinal :: t -> a (bound at fist.hs:7:1)
|
1 | ordinal 0 = []
| ^^^^^^^^^^^^^^^...

Now what I imagine might have gone wrong here is that the list is not of homogeneous type. But how would I switch to tuples then? Is there such a thing as "tuple comprehension"?

like image 718
AlgebraicsAnonymous Avatar asked Sep 09 '21 22:09

AlgebraicsAnonymous


2 Answers

The result of this function is a single empty value, or a list of such, or a list of lists, or a list of lists of lists, etc., depending on the input number. There is no single list type which can represent all these values.

... or is there? That type is not a list (i.e. []) which only represents a single flat sequences of values, but there is such a type:

data Ordinal = Zero | Ordinal [Ordinal] deriving Show

and your function should be modified to wrap each such level of list nesting in an Ordinal constructor:

ordinal 0 = Zero
ordinal x = Ordinal [ ordinal n | n<-[1..(x-1)] ]

Example:

*Main> ordinal 3
Ordinal [Ordinal [],Ordinal [Ordinal []],Ordinal [Ordinal []]
like image 57
user2407038 Avatar answered Nov 18 '22 03:11

user2407038


First, lists aren't sets.

Second, lists require all elements to have the same type, so you can't have lists of different nesting depth in one list.

But from the “everything is a set” perspective that such constructions as Von Neumann ordinals are based on, you can just define a “universal type” based on sets:

import qualified Data.Set as Set

newtype UntypedSet = UntypedSet { getUntypedSet :: Set.Set UntypedSet }
 deriving (Eq, Ord, Show)

ordinal :: Int -> UntypedSet
ordinal 0 = UntypedSet $ Set.empty
ordinal x = UntypedSet $ Set.fromList [ ordinal n | n <- [0..x-1] ]

Note the definition [1..x-1] was actually wrong in your implemetation, it should be [0..x-1].

If you want to go quirky (not necessarily recommended), you can actually still use “list” notation:

{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE TypeFamilies    #-}

import qualified Data.Set as Set
import GHC.Exts (IsList(..))

newtype UntypedSet = UntypedSet { getUntypedSet :: Set.Set UntypedSet }
 deriving (Eq, Ord)

instance IsList UntypedSet where
  type Item UntypedSet = UntypedSet
  fromList = UntypedSet . Set.fromList
  toList (UntypedSet s) = Set.toList s

instance Show UntypedSet where
  show = show . toList


ordinal :: Int -> UntypedSet
ordinal 0 = []
ordinal x = fromList [ ordinal n | n <- [0..x-1] ]

Then,

*Main> ordinal 4
[[],[[]],[[],[[]]],[[],[[]],[[],[[]]]]]
like image 31
leftaroundabout Avatar answered Nov 18 '22 03:11

leftaroundabout