16

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
Will Ness
  • 70,110
  • 9
  • 98
  • 181
js2010
  • 23,033
  • 6
  • 64
  • 66
  • How would you define it's postfix form? It is not a function that accepts a number and returns a finite range spanning up to this number. – bipll Sep 01 '20 at 20:50
  • @bipll Ok, I took away the parentheses. – js2010 Sep 01 '20 at 22:15
  • Regardless parentheses, `a ..` is a valid expression, and it is not a function, likewise `a, a + 3 ..`. How would you define them? – bipll Sep 02 '20 at 08:04

1 Answers1

21

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.

Will Ness
  • 70,110
  • 9
  • 98
  • 181