I know Puppet classes tend to be assigned with two colons. But I don't fully understand what the :: does. When are two colons necessary for defining a class in a Puppet file?
They are used for namespace seperators. It is analogous to the /
Related
In Haskell, is it possible to define a data type within a function scope?
For example, I am writing a function f :: [(Char, Int)] -> [(Char, String)]. In the implementation of the function, I will build a tree from the input list, and then traverse the tree to build the output list. One solution is to define a new Tree data type specific to my problem, along with two helper functions, one to translate the input list into the Tree and the other to walk the Tree and build the output list.
Now the two helper functions can easily be pulled into the scope of f by putting them into a where clause, but what about the interim nonce type Tree? It seems ugly to pollute the namespace by defining it outside the function scope, but I don't know how else to do it.
For context, it turns out I am computing a Huffman encoding. I am not particularly interested in finding an alternative algorithm at this point, as I suspect that it will often be useful in Haskell to define helper data types between helper functions, so I am interested in general approaches to this.
No, it's impossible.
In Haskell modules and qualified imports are supposed to resolve all namespacing problems, like yours or the notorious record field names collision.
So you want a type to be visible only to a certain function? Put that type and that function in a new module and (optionally) export just the function.
Sure, by following this convention you will end up with more modules than usual, but if you think about it, this is not actually that different from many other languages. E.g., in Java it's conventional to put each class in a separate file, no matter how small the class is.
I have to mention though that far from most people in the community actually follow this convention. You can often see cryptic names used to work around this. Personally I don't find such an approach very clean and would rather recommend using modules.
Is there a Data.Binary instance for Data.Time.Calendar.Day?
More generally, what is one supposed to do if Data.Binary have not been provided for a particular datatype in a widely used library?
If you just create a Binary instance and place it in your module then you'll be creating an orphan instance which can cause a lot of confusion later when someone imports your module---it'll drag along that orphan instance and possibly conflict with their understanding of how dates should be made Binary.
If you have a very canonical instance, try pushing it to the library author. It's easy to add the instance if it's a good idea and it can benefit anyone who uses that library.
If that isn't an option (or if you have a non-canonical instance) then you probably want to create a newtype wrapper. They're "free" in that the compiler deletes them automatically, but they allow a type to take on an entirely new identity with new typeclass instances.
I've done this before to handle particular parses of, for instance, "dates in this format" compared to Date broadly.
Suppose I have the following class:
class P a where
nameOf :: a -> String
I would like to declare that all instances of this class are automatically instances of Show. My first attempt would be the following:
instance P a => Show a where
show = nameOf
My first attempt to go this way yesterday resulted in a rabbit warren of language extensions: I was first told to switch on flexible instances, then undecidable instances, then overlapping instances, and finally getting an error about overlapping instance declarations. I gave up and returned to repeating the code. However, this fundamentally seems like a very simple demand, and one that should be easily satisfied.
So, two questions:
Is there a trivially easy way to do this that I've just missed?
Why do I get an overlapping instances problem? I can see why I might need UndecidableInstances, since I seem to be violating the Paterson condition, but there are no overlapping instances around here: there are no instances of P, even. Why does the typechecker believe there are multiple instances for Show Double (as seems to be the case in this toy example)?
You get the overlapping instances error because some of your instances of P may have other instances of Show and then the compiler won't be able to decide which ones to use. If you have an instance of P for Double, then there you go, you get two instances of Show for Double: yours general one and the one already declared in Haskell's base library. How this error is triggered is correctly stated by #augustss in the comments to your question. For more info see the specs.
As you already know, there is no way to achieve what you're trying without the UndecidableInstances. When you enable that flag you must understand that you're taking over the compiler's responsibility to ensure that there won't arise any conflicting instances. This means that, of course, there mustn't be any other instances of Show produced in your library. This also means that your library won't export the P class, which will erase the possibility of users of the library declaring the conflicting instances.
If your case somehow conflicts with the said above, it's a reliable sign of that there must be something wrong with it. And in fact there is...
What you're trying to achieve is incorrect above all. You are missing several important points about the Show typeclass, distinguishing it from constructs like a toString method of popular OO languages:
From Show's haddock:
The result of show is a syntactically correct Haskell expression containing only constants, given the fixity declarations in force at the point where the type is declared. It contains only the constructor names defined in the data type, parentheses, and spaces. When labelled constructor fields are used, braces, commas, field names, and equal signs are also used.
In other words, declaring an instance of Show, which does not produce a valid Haskell expression, is incorrect per se.
Given the above it just doesn't make sense to declare a custom instance of Show when the type allows to simply derive it.
When a type does not allow to derive it (e.g., GADT), generally you'll still have to stick to type-specific instances to produce correct results.
So, if you need a custom representation function, you shouldn't use Show for that. Just declare a custom class, e.g.:
class Repr a where
repr :: a -> String
and approach the instances declaration responsibly.
I've read about some of the issues with Haskell records, in particular, the fact that two elements in the same module can not have the same name.
I understand you can work around this by having separate modules, but I didn't want to do that and instead tried this approach:
class HasX a where
x :: a -> X
data D1 = D1 { d1_x :: X, ... }
instance HasX D1 where
x = d1_x
data D2 = D2 { d2_x :: X, ... }
instance HasX D2 where
x = d2_x
(This only does gets, not sets, I'd of course need to write more code to do sets).
However, it seems the class and instance declarations for all this seem like a like of boilerplate which should be able to be eliminated, using template haskell or something else.
Is there a library or extension to GHC that makes such an approach less messy to write?
It seems Data.Has encapsulates a lot of what you're looking for. In their vocabulary they I think that their Knows type-class is closer to your Has, and it also provides a signature for injection as well.
They also use a labeling mechanism to treat an issue that I don't think you've considered yet: records which contain fields that have the same type. They use type-level labels to do this disambiguation.
For convenience, there also seems to be some support that provides a generator for the Has instance with template Haskell in Has-TH
You can find more type-level labels and other record-relevant material in works of the Oleg the Type Magician, like OOHaskell (also with Ralf Lämmel).
data-accessor-template may at least help to write the set/get accessors. Maybe some people can come up with the Template Haskell code for generation of classes and instances for every record field name.
However, I do not use the Template Haskell stuff myself. It restricts you to GHC, and even to specific GHC versions, since Template Haskell changes between different GHC versions. Having one (major) record per module really pays off.
I'm trying to reduce my confusion about Haskell's syntax and would like to find out what the separate namespaces are in Haskell.
Namespaces meaning syntactical namespaces corresponding to the various symbols tables the compiler manages, not name scopes defined in code.
For example:
Value names (like function names)
Data constructors
Type constructors
Type parameters (in type definitions)
instances ?
...?
I'm interested because I'm having trouble reading Haskell code (definitely more than with any other language) because I frequently have a hard time figuring out what exactly I'm looking at (especially with data/type constructors/type declarations).
Haskell seems to reuse a handful of syntactical constructs (esp. <name> <name> ...) in many places and relies on context - just turns out that the compiler is a lot better at this than me...
The Haskell Report §1.4 says
There are six kinds of names in Haskell: those for variables and
constructors denote values; those for type variables, type
constructors, and type classes refer to entities related to the type
system; and module names refer to modules. There are two constraints
on naming:
Names for variables and type variables are identifiers beginning with lowercase letters or underscore; the other four kinds of names
are identifiers beginning with uppercase letters.
An identifier must not be used as the name of a type constructor and a class in the same scope.
These are the only constraints; for example, Int may simultaneously be
the name of a module, class, and constructor within a single scope.
The confusion can be avoided if you make sure you understand what you are reading:
an expression: here every upper case name is a data constructor or a qualified variable or constructor whereas lower case are values
a type: here every upper case name is a type constructor or class name, whereas lower case names are type variables.