Search code examples
haskellenumsenumerationtypeclassdefinition

Where is .. defined?


I'm just wondering whether .. is actually defined in Haskell code anywhere, like in the Prelude? Is enumFromTo the same thing? I don't get which is the definition?

enumFromTo x y  =  map toEnum [fromEnum x .. fromEnum y]

[ e1 .. e3 ]  =  enumFromTo e1 e3

Solution

  • It's a part of the syntax, specified in the Report, section 3.10.

    Yes it gets translated into code using enumFrom etc. functions:

    enter image description here

    To your edit of the question: the definitions you show are "default definitions" in the Enum typeclass. It says so right there in the Prelude you linked:

    class  Enum a  where
        succ, pred       :: a -> a
        toEnum           :: Int -> a
        fromEnum         :: a -> Int
        enumFrom         :: a -> [a]             -- [n..]
        enumFromThen     :: a -> a -> [a]        -- [n,n'..]
        enumFromTo       :: a -> a -> [a]        -- [n..m]
        enumFromThenTo   :: a -> a -> a -> [a]   -- [n,n'..m]
    
            -- Minimal complete definition:
            --      toEnum, fromEnum
    --             _______                                      -- ____
    -- NOTE: these default methods only make sense for types    -- **** NB
    --   that map injectively into Int using fromEnum
    --  and toEnum.
        succ             =  toEnum . (+1) . fromEnum
        pred             =  toEnum . (subtract 1) . fromEnum
        enumFrom x       =  map toEnum [fromEnum x ..]
        enumFromTo x y   =  map toEnum [fromEnum x .. fromEnum y]
        enumFromThen x y =  map toEnum [fromEnum x, fromEnum y ..]
        enumFromThenTo x y z = 
                            map toEnum [fromEnum x, fromEnum y .. fromEnum z]
    

    So each type a that is in Enum must provide the definitions for at least toEnum :: Int -> a and fromEnum :: a -> Int. If it doesn't provide its own definition for e.g. enumFromTo :: a -> a -> [a] then its default definition will be used:

    enumFromTo :: a -> a -> [a]
    enumFromTo x  y   =  map  toEnum  [fromEnum x .. fromEnum y ]
    --        └a┘└a┘                           └a┘           └a┘
    --                                 └──Int────┘   └──Int────┘
    --                       └Int->a┘ └─────────[Int]───────────┘
    --                   └───────────────[a]────────────────────┘
    

    And for the Int type itself there is a specific definition defined somewhere in the library, so the default definition of enumFromTo is not used for Int, thus there is no vicious circle.