Is there an alternative to writing to Haskell?

I am looking for a better alternative to standard records, which are only auto-generated access functions via tuples. The problem is with name problems, in which records with the same field names have the same access functions.

+8
haskell
source share
6 answers

I am using lens with makeFields TH function. This allows me to do something like this:

{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TemplateHaskell #-} import Control.Lens data Person = Person { _personFirstName :: String , _personLastName :: String , _personEmail :: String } data Corp = Corp { _corpName :: String , _corpEmail :: String } makeFields ''Person makeFields ''Corp main = let myGuy = Person "Test" "Guy" "email@account.com" myCorp = Corp "ABC" "sales@abc.com" in putStrLn $ "personal email: " ++ (myGuy^.email) ++ "corp email: " ++ (myCorp^.email) 

What happens here is that the makeFields function creates HasName and HasEmail class types that have one member (name or email address). He also creates instances for them for these types. MultiParamTypeClasses and functional dependencies allow you to "overload" these elements for different data types.

makeFields, by convention, is going to do this for each record constructor that starts with an underscore, and the name it chooses for the field is the balance of the name of the constructor starting with the first capital letter. Thus, _corpEmail creates the email field.

Now these โ€œfieldsโ€ are lenses, and there are many functions that you can apply with them. To simply get the value from a record, you can use the "view" function, for example:

view email myGuy

There is an inverse function called (^.), Which takes the record as the first parameter, and the lens as the second. I personally prefer this style in many cases, but I still often use representation, especially in the dotless style.

The LOT lens is more than just this feature - I personally find this feature irresistible, but in fact the most important thing that it does for you is letting you compose these lenses to make updates in the depths of the data structures. Composition is simple with an operator (.), Like any other function; so if we assume that my example had the _corpPresident :: Person field, I could do this:

  putStrLn $ myCorp^.president.email 

Or - change this nested value:

 let newCorp = set president.email "changedemail@address.com" myCorp 

Or the same thing (with great operator frenzy):

 let newCorp = myCorp & president.email .~ "changedemail@address.com" 

There is much more, and I barely scratched the surface. The hackage docs are good, but I think the best way to get started is with a field guide that is in Github repository read mode .

+6
source share

My policy for namespace conflicts is to put conflicting types in separate modules. You can then use the Haskell name distribution tools to resolve conflicts. However, I would like Haskell to have a way to define multiple namespaces within the same module.

+5
source share

From Haskel Report 98

Operations using field labels are described in section 3.15. A data label can use the same field label in several constructors if the field is typed in all cases the same after the extension of the type synonym. A label cannot be used by more than one type. Field names share the top-level namespace with regular class variables and methods and should not conflict with other top-level names in the scope.

No, there is no way.

I usually do something like

 data Person = Person { personName :: String , personAge :: Int } deriving (Eq, Show) data Pet = Pet { petName :: String , petAge :: Int } deriving (Eq, Show) class Living a where name :: a -> String age :: a -> Int instance Living Person where name = personName age = personAge instance Living Pet where name = petName age = petAge 

But honestly, I rarely need (or use) such a type class. It shows how you can use the same accessor for different types of records.

+4
source share

A Vinyl represents one solution. To quote authors:

Vinyl is a general solution to the problem of recordings in Haskell using string level levels and other modern GHC features, including static structural typing (with subtype ratios) and automatic polymorphic lenses. All this is possible without a Haskell template.

If, however, the amount of memory is troubling for you, I would advise you to go with Gabriel's suggestion, as vinyl records are heavier.

In general, the Records problem is a notorious problem, and since the late 90s (you can imagine) great solutions have been proposed. But since their implementation was difficult, no one has reached it. I recently initiated a related discussion about Reddit , you can get interesting information there. It turns out that some work is being done at that time, at least with regard to the problem with names, and it is expected that its results will soon appear in the world.

+1
source share

The easiest way to enable the DisambiguateRecordFields extension. This does not change much at all, it uses mainly Haskell98 data declarations, but allows you to reuse field names. I found this to work very well, especially if you take one more step towards RecordWildCards .

+1
source share

NamedFieldPuns with DisambiguateRecordFields, but this is limited by function and allows bindings rather than arbitrary expressions: http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/syntax-extns.html

0
source share

All Articles