Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an alternative to records in Haskell?

Tags:

haskell

I am looking for a better alternative to the standard records which are just auto generated accessor functions over tuples. The problem is the naming issues where records with the same names of their fields get same accessor functions.

like image 313
Trident D'Gao Avatar asked Jan 03 '14 20:01

Trident D'Gao


People also ask

What are some of the Haskell alternatives?

So in this article, we will be discussing eight Haskell alternative programming languages in a short brief. Some of the Haskell alternatives which we will be discussing are Java, Lua, Dart, Scala, Kotlin, Haxe, Nim, Asp.net, etc.

What is Haskell programming language?

Haskell is fully cum purely functional computer programming language which is a bit lazy and polymorphically statically typed. The main part is that it is purely different from other programming languages in wide aspects.

What are record accessors in Haskell?

In this example, two record accessors are defined, age and name, which allow us to access the age and name fields respectively. Record accessors are just Haskell functions which are automatically generated by the compiler. As such, they are used like ordinary Haskell functions.

Should I learn Scala or Haskell?

The type system is too complicated yet still less powerful than Haskell's. Scala offers type inference, which, while giving the same safety as Java's type system, allows programmers to focus on the code itself, rather than on updating type annotations. Aside from Java itself, Scala is by far the most popular of the many JVM languages.


2 Answers

I am using lens with the makeFields TH function. This lets me 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 protected]" 
      myCorp = Corp "ABC" "[email protected]" in
      putStrLn $ "personal email: " ++ (myGuy^.email) ++
                 "corp email: " ++ (myCorp^.email) 

What is happening here is that the makeFields function creates type-classes HasName and HasEmail that have a single member (name, or email). It also creates instances for them for these types. MultiParamTypeClasses and Functional Dependencies make it possible to "overload" these members for different data types.

makeFields by convention is going to do this for each record constructor that begins with an underscore, and the name it will choose for the field is the balance of the constructor name beginning at the first capital letter. So _corpEmail makes an "email" field.

Now these "fields" are lenses, and there are a lot of functions that you can apply with them. To simply get the value from a record you could use the "view" function, e.g.:

view email myGuy

There is an inverse of this function called (^.), which takes a record as the first parameter and the lens as the second. I personally prefer this style in many cases but I still use view sometimes as well, particularly in a points-free style.

Lens is a LOT bigger than just this feature - I personally find this feature compelling but really the most important thing it does for you is enabling you to compose these lenses to make updates deep in data structures. Composition is simply with the (.) operator like any other function; so if we imagine my example had a _corpPresident :: Person field, I could do this:

 putStrLn $ myCorp^.president.email 

Or - to change this nested value :

let newCorp = set president.email "[email protected]" myCorp 

Or same thing (with more operator madness) :

let newCorp = myCorp & president.email .~ "[email protected]"

There is a lot more and I've hardly scratched the surface myself. The hackage docs are good but I think the best way to get started is with the field guide which is in the readme of the Github repository.

like image 92
Jeremy Avatar answered Oct 18 '22 22:10

Jeremy


My policy for namespace conflicts is to put conflicting types in separate modules. Then you can use Haskell's namespacing tools to resolve conflicts. However, I wish Haskell had a way to define multiple namespaces within a single module.

like image 37
Gabriella Gonzalez Avatar answered Oct 18 '22 22:10

Gabriella Gonzalez