Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do bracketed double dots mean in Haskell?

I understand that .. can be used in ranges--i.e., [1..3] == [1,2,3], and [10..] is an infinite list starting at 10.

However, recently I've started seeing these double dots inside brackets too. Either as (..) or {..}.

For example, an import statement can read import Colog (HasLog (..))

My first intuition here is to think that this means that HasLog has several components and we are explicitly importing all of them. But how does that differ from simply importing HasLog, without the (..)?

Further, how does (..) differ from {..}?

like image 865
lantejoula Avatar asked Jun 30 '21 10:06

lantejoula


People also ask

What does <$> mean in Haskell?

It's merely an infix synonym for fmap , so you can write e.g. Prelude> (*2) <$> [1.. 3] [2,4,6] Prelude> show <$> Just 11 Just "11" Like most infix functions, it is not built-in syntax, just a function definition. But functors are such a fundamental tool that <$> is found pretty much everywhere.

What is ==> in Haskell?

Haskell Language QuickCheck Using implication (==>) to check properties with preconditions.

What does in do in Haskell?

in goes along with let to name one or more local expressions in a pure function.


Video Answer


1 Answers

(..) and {..} are both ways to bring names associated with data types in scope, but they're very different and used in different contexts.

  • The (..) syntax is specifically used for import and export lists. It's part of the syntax for declaring which constructors and/or record fields of a data type you want to import/export. For example, if I have a module

    module FooM where
    data Foo = F0 | F1 | F2
    data Bar = Bar { b0 :: Int, b1 :: Char }
    

    then this compiles

    import FooM ( Foo(F1,F2), Bar(b1) )
    fu = F1
    ba = b1
    

    but this doesn't

    import FooM ( Foo(F1,F2) )
    fu = F0
    

    because I've only imported the F1 and F2 constructors, not F0. If I write

    import FooM ( Foo(..), Bar(..) )
    fu = F0
    ba = b0
    

    it also works, because this imports all constructors and record labels. By contrast, with

    import FooM ( Foo )
    fu = F0
    

    you don't import any constructors or record fields at all, but only Foo as an opaque type, so here fu = F0 also won't compile. (This often exploited in export lists, if you want the inner structure of a data type to be “private” and only manipulable with utility functions, smart constructors etc..)

  • {..} is part of the RecordWildCards extension. In a nutshell, it turns the names of all record labels that would apply to a parameter into locally-scoped variables.
    I would advice against using this, it's one of those extensions that tried to address the shortcomings of Haskell's record system – with IMO not much success. Better to either use records in the traditional way, or auto-generate some lenses and use these to completely avoid the record issues.

like image 158
leftaroundabout Avatar answered Oct 22 '22 16:10

leftaroundabout