Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: Confusion with own data types. Record syntax and unique fields

Tags:

haskell

I just uncovered this confusion and would like a confirmation that it is what it is. Unless, of course, I am just missing something.

Say, I have these data declarations:

data VmInfo = VmInfo {name, index, id :: String} deriving (Show)
data HostInfo = HostInfo {name, index, id :: String} deriving (Show)

vm = VmInfo "vm1" "01" "74653"
host = HostInfo "host1" "02" "98732"

What I always thought and what seems to be so natural and logical is this:

vmName = vm.name
hostName = host.name

But this, obviously, does not work. I got this.


Questions

So my questions are.

  • When I create a data type with record syntax, do I have to make sure that all the fields have unique names? If yes - why?

  • Is there a clean way or something similar to a "scope resolution operator", like :: or ., etc., so that Haskell distinguishes which data type the name (or any other none unique fields) belongs to and returns the correct result?

  • What is the correct way to deal with this if I have several declarations with the same field names?


As a side note.

In general, I need to return data types similar to the above example. First I returned them as tuples (seemed to me the correct way at the time). But tuples are hard to work with as it is impossible to extract individual parts of a complex type as easy as with the lists using "!!". So next thing I thought of the dictionaries/hashes. When I tried using dictionaries I thought what is the point of having own data types then? Playing/learning data types I encountered the fact that led me to the above question. So it looks like it is easier for me to use dictionaries instead of own data types as I can use the same fields for different objects.


Can you please elaborate on this and tell me how it is done in real world?

like image 505
r.sendecky Avatar asked Feb 20 '12 00:02

r.sendecky


People also ask

How data types are combined in Haskell?

You can combine multiple types with an and (for example, a name is a String and another String ), or you can combine types with an or (for example, a Bool is a True data constructor or a False data constructor). Types that are made by combining other types with an and are called product types.

What is the difference between data and type in Haskell?

Type and data type refer to exactly the same concept. The Haskell keywords type and data are different, though: data allows you to introduce a new algebraic data type, while type just makes a type synonym. See the Haskell wiki for details.

How do you declare types in Haskell?

Haskell has three basic ways to declare a new type: The data declaration, which defines new data types. The type declaration for type synonyms, that is, alternative names for existing types. The newtype declaration, which defines new data types equivalent to existing ones.

Does Haskell have different types?

Everything in Haskell has a type, so the compiler can reason quite a lot about your program before compiling it. Unlike Java or Pascal, Haskell has type inference.


2 Answers

Haskell record syntax is a bit of a hack, but the record name emerges as a function, and that function has to have a unique type. So you can share record-field names among constructors of a single datatype but not among distinct datatypes.

What is the correct way to deal with this if I have several declarations with the same field names?

You can't. You have to use distinct field names. If you want an overloaded name to select from a record, you can try using a type class. But basically, field names in Haskell don't work the way they do in say, C or Pascal. Calling it "record syntax" might have been a mistake.

But tuples are hard to work with as it is impossible to extract individual parts of a complex type

Actually, this can be quite easy using pattern matching. Example

smallId :: VmInfo -> Bool
smallId (VmInfo { vmId = n }) = n < 10

As to how this is done in the "real world", Haskell programmers tend to rely heavily on knowing what type each field is at compile time. If you want the type of a field to vary, a Haskell programmer introduces a type parameter to carry varying information. Example

data VmInfo a = VmInfo { vmId :: Int, vmName :: String, vmInfo :: a }

Now you can have VmInfo String, VmInfo Dictionary, VmInfo Node, or whatever you want.

Summary: each field name must belong to a unique type, and experienced Haskell programmers work with the static type system instead of trying to work around it. And you definitely want to learn about pattern matching.

like image 147
Norman Ramsey Avatar answered Oct 26 '22 19:10

Norman Ramsey


There are more reasons why this doesn't work: lowercase typenames and data constructors, OO-language-style member access with .. In Haskell, those member access functions actually are free functions, i.e. vmName = name vm rather than vmName = vm.name, that's why they can't have same names in different data types.

If you really want functions that can operate on both VmInfo and HostInfo objects, you need a type class, such as

class MachineInfo m where
  name :: m -> String
  index :: m -> String    -- why String anyway? Shouldn't this be an Int?
  id :: m -> String

and make instances

instance MachineInfo VmInfo where
  name (VmInfo vmName _ _) = vmName
  index (VmInfo _ vmIndex _) = vmIndex
  ...
instance MachineInfo HostInfo where
  ...

Then name machine will work if machine is a VmInfo as well as if it's a HostInfo.

like image 42
leftaroundabout Avatar answered Oct 26 '22 18:10

leftaroundabout