Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell syntax: the meaning of {..} and @

Tags:

haskell

yesod

I'm just learning Yesod/Haskell.

In the following code (http://www.yesodweb.com/book/restful-content) there are two things I don't understand (and a subsequent question).

  1. {..} - what does that mean? (It's a hard term to google for.)
  2. person@Person - what does the @ sign do?
  3. Is there a way I can find answers to ungooglable Haskell syntax, without bothering you all on StackOverflow?

code:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes       #-}
{-# LANGUAGE RecordWildCards   #-}
{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE TypeFamilies      #-}
import           Data.Text (Text)
import           Yesod

data Person = Person
    { name :: Text
    , age  :: Int
    }

instance ToJSON Person where
    toJSON Person {..} = object
        [ "name" .= name
        , "age"  .= age
        ]

data App = App

mkYesod "App" [parseRoutes|
/ HomeR GET
|]

instance Yesod App

getHomeR :: Handler TypedContent
getHomeR = selectRep $ do
    provideRep $ return
        [shamlet|
            <p>Hello, my name is #{name} and I am #{age} years old.
        |]
    provideJson person
  where
    person@Person {..} = Person "Michael" 28

main :: IO ()
main = warp 3000 App
like image 546
fadedbee Avatar asked Sep 24 '13 10:09

fadedbee


2 Answers

For points 1 and 2, I guess you're referring to line

person@Person {..}

The {..} comes from the RecordWildcards extension. Basically it brings in scope all fields of the Person datatype. That's why you can use name and age in the Hamlet template above.

The @ serves as an alias. Everytime you see id@deconstructor_expr you can use id for the entire value which is deconstructed by deconstructor_expr. For example you can have

f (x:a@(y:_)) = a

and a will be the tail of the argument list as long as the list has at least 2 elements (that is f is tail for lists with more than 2 elements).

Without these two, the entire function would have to change to

getHomeR :: Handler TypedContent
getHomeR = selectRep $ do
    provideRep $ return
        [shamlet|
            <p>Hello, my name is #{name'} and I am #{age'} years old.
        |]
    provideJson person
  where
    person = Person "Michael" 28
    name' = name person
    age' = age person

Observe that name and age are functions from the record to the specific field and that means that you have to use other names for the values (the '-ending variables). Also, because we no longer use @ we need separate lines for the person and for the fields.

Another alternative would be

getHomeR :: Handler TypedContent
getHomeR = selectRep $ do
    provideRep $ return
        [shamlet|
            <p>Hello, my name is #{name person} and I am #{age person} years old.
        |]
    provideJson person
  where
    person = Person "Michael" 28

You still need to call the name and age functions.

For point 3, a possibility is to go on IRC on #haskell and ask there. Anyway, the same people from there are here, it's not a bother in asking.

like image 82
Mihai Maruseac Avatar answered Sep 22 '22 07:09

Mihai Maruseac


Adding to other answers, for searching for ungooglable syntax use symbolhound.com.

like image 41
Nikita Volkov Avatar answered Sep 23 '22 07:09

Nikita Volkov