Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can record's field be matched with some value and assigned to a parameter at the same time?

Tags:

haskell

After a relatively brief text on Haskell wiki about pattern matching of records, I'm not sure if record's field can be matched with some value and assigned to a parameter at the same time.

-- Sample record type
data Rec = Rec { uid :: Int, name :: String }

-- Function to update Rec's fields
updateRec :: Rec -> Rec

-- basic matching with record data constructor
updateRec (Rec _ []) = Rec 0 "Nobody"

-- dtto with as-pattern at 2nd param
updateRec (Rec idn ns@"Alice") = Rec (idn+1) (ns ++ "+1")

-- basic matching by fields values
updateRec Rec {name = "Bob", uid = 42} = Rec (10^6) "SuperBob"

-- Q: how to match by name field and assign it's value ?
updateRec Rec {name = "Bob", uid = idn} =
    Rec {uid = (idn+1), name = ("Bob" ++ "+1")}

-- Q: as-pattern works only on the whole record, not on a field
updateRec rec@(Rec {name = "Bob", uid = idn}) =
    Rec {uid = (idn+1), name = (name rec ++ "+1")}

-- Q: pattern guards do work, but they are a bit clumsy
updateRec Rec {name = uname, uid = idn}
    | uname == "Bob" = Rec {uid = (idn+1), name = (uname ++ "+1")}
    | otherwise = ...

So is there some concise way to pattern match by record's field and assign its value at the same time?

Note: I would like to avoid specific GHC's extensions.

like image 869
David Unric Avatar asked Jan 30 '12 15:01

David Unric


1 Answers

The field names are patterns themselves, so you can use another as-pattern:

updateRec Rec {name = uname@"Bob", uid = idn@42} = ...

There isn't any more concise way to do this, standard or with GHC extensions. Of course, for a case as simple as this, you could simply omit the bindings and use "Bob" and 42 directly in the function body.

like image 198
ehird Avatar answered Oct 28 '22 07:10

ehird