Haskell, unnamed command line arguments for optparse-generic - haskell

I'm using optparse-generic to parse the command line arguments of a program called example. I have a datatype with named fields (record syntax). For example:
data Example = Example { foo :: Int, bar :: String } deriving (Generic, Show)
This generates a program which can be called as follows:
./example --foo 42 --bar "baz"
How can I tell optparse-generic that bar should be an unnamed, mandatory, positional command line argument. That means, I don't want to type --bar when I call example. For example, I want to call example the following:
./example --foo 42 "baz"

optparse-generic does not support generating such a parser from a single data type definition since Haskell does not support records with both labeled and unlabeled fields.
However, what you can do is generate one data type for all the labeled fields and one type for the unlabeled fields and then combine them using Applicative operations, like this:
data Labeled = Labeled { foo :: Int } deriving (Generic, Show)
instance ParseRecord Labeled
data Unlabeled = Unlabeled String deriving (Generic, Show)
instance ParseRecord Unlabeled
data Mixed = Mixed Labeled Unlabeled deriving (Show)
instance ParseRecord Mixed where
parseRecord = Mixed <$> parseRecord <*> parseRecord

Related

Generating Swagger for Haskell union type

I have a data structure of the following form:
data MyType =
Foo Int String
| Bar Int Int
| Baz String
I've manually generated an aeson ToJSON instance:
instance ToJSON MyType where
toJSON (Foo i s) = object [
"tag" .= ("foo" :: Text),
"intField" .= i,
"stringField" = s]
-- and so on.
Now I want a Swagger schema for it. Because I have a custom ToJSON instance I'm going to have to define a matching instance of ToSchema. I could just declare it as a list of mostly-optional field names and a mandatory tag string, but it really ought to list the possible tag values and associate them with different fields.
The OpenAPI specification talks about the discriminator object for doing this, and I've found the corresponding function in the Haskell swagger2 package. But I can't see how to get the mapping from discriminator value to sub-schema. Does anyone have any examples of how to do this?

Haskell. Why does read function does not work with custom data type though I used deriving?

Read function does not work properly with custom data type.
data TwoInts = Int Int
deriving (Read, Show)
conv :: String -> TwoInts
conv s = read s
When i load this function with ghci
ghci conv.hs
It loads properly, but when i call it
conv "15 14"
i am getting following error:
*** Exception: Prelude.read: no parse
As suggested, your data type:
data TwoInts = Int Int
deriving (Read, Show)
describes a constructor named Int that accepts a type Int. If you were to use records, maybe this is more clear:
data TwoInts = Int { int :: Int}
deriving (Read, Show)
The solution as suggested in the comments is to name your constructor something else, e.g.,
data TwoInts = TwoInts Int Int
deriving (Read, Show)

Is it possible to have both positional and named CLI options using optparse-generic?

I'd like to make a CLI using the Haskell library optparse-generic. The documentation shows an example for positional arguments, and another for options (e.g. --flag=True), but I can't figure out how to combine the two. I've tried something like this:
data CLI = CLI Options Files deriving (Generic, Show)
data Files = Files [String] deriving (Generic, Show)
data Options = Options { colorMap :: String <?> "Color mapping to use."
} deriving (Generic, Show)
instance ParseRecord CLI
But that doesn't seem to be legal.

Haskell, documentation for unlabeled command line arguments in optparse-generic

I'm using optparse-generic to parse the command line arguments of a program called example. I have a datatype with an unnamed field. For example:
data Unlabeled = Unlabeled String deriving (Generic, Show)
This generates a program which can be called as follows: ./exmaple "foo". However, for the user, there is no documentation what the String-parameter is about. In particular, ./example --help does not give any valuable information about this positional String argument ./example expects.
Using named datatypes (record syntax), it is possible to add documentation to the datatype. For example
data Labeled = Labeled {name :: String <?> "Select the foo"} deriving (Generic, Show)
This generates help text for the program. For example, when called ./example --help, it will display --name STRING Select the foo.
How can I add documentation to unnamed datatypes in the same way as I can do for record-syntax-datatypes?
data Labeled = Labeled (String <?> "Select the foo") will give you
...
STRING Select the foo
...
in the --help message. To perhaps clarify, the <?> is simply a type constructor, it is just syntactically an operator. Maybe fun fact: you can write data X = X (Int `Either` Bool) as well.

Template Haskell data declarations that derive Show

The following doesn't compile:
import Language.Haskell.TH
makeAlpha n = [d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]
I can't make out what the error means at all:
Can't derive instances where the instance context mentions
type variables that are not data type parameters
Offending constraint: Show t_d
When deriving the instance for (Show Alpha)
In the Template Haskell quotation
[d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]
In the expression:
[d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]
Is it possible to do derivations like this?
This problem arises because TH quotes are type checked when they are compiled, with splices replaced by variables. This is usually a good idea, because it allows many kinds of problems to be detected before the splice is run, but in some cases this can make the compiler wrongfully reject a splice that would generate valid code.
In this case, this means that the compiler tries to check this code:
data Alpha = Alpha t deriving (Show, Read)
This doesn't work because the derived Show and Read instances need to use Show and Read for t, but since t is not a type parameter of Alpha, it cannot add the necessary constraints. Of course, when this splice is run, t is replaced by a concrete type, so the appropriate instances will be available without the need for any constraints, so this is one of the cases where the compiler is being over-cautious.
The workaround is to not use quoting, but instead use TH combinators, which are not subject to these extra checks. It's messy, but it works:
makeAlpha n = sequence [dataD (cxt []) alpha []
[normalC alpha [strictType notStrict (conT n)]] [''Show, ''Read]]
where alpha = mkName "Alpha"
There has been some talk about relaxing the checks done on quotes, but for now you'll just have to deal with it.

Resources