How to ignore a polymorph readable type, while reading? - haskell

I have a problem similar to:
data Foo a = Foo { myInt :: Integer, myValue :: a } deriving Read
bar :: String -> Integer
bar = myInt . read
main = print $ bar stringWithFooOfa
i don't want to use something like read . (!!1) . words, if i don't need to.

Add a type annotation to read. As commenters suggested, Haskell has no way of knowing what you're trying to read since you immediately turn it into an Int. To be more clear, consider this example:
data Foo a = Foo { myInt :: Integer, myValue :: a } deriving Read
data Foo2 a = Foo { myInt2 :: Integer } deriving Read
bar :: String -> Integer
bar = myInt . read
Now there are two very different behaviors for bar possible and it's hard to know which is correct.
To tell Haskell which one you want, use an inline annotation around read:
bar :: String -> Integer
bar = myInt . (read :: String -> Foo ())
Notice that I pick an a, too. Otherwise, we'll be in the same boat as above but just with a instead of Foo.

Related

What is the idiomatic way to access part of Algebraic data type in Haskell?

There is an easier way to call function test with value x than using case expression?
data FooBar = Foo Int | Bar String
test :: Maybe Int -> Bool -- Int from Foo constructor
x :: FooBar
One easier way is to define a helper to get you part of the way there:
data FooBar = Foo Int | Bar String
foo :: FooBar -> Maybe Int
foo (Foo x) = Just x
foo _ = Nothing
test :: Maybe Int -> Bool
x :: FooBar
result :: Bool
result = test . foo $ x
If you're the one defining test, you could also just define it differently to make things easier on yourself:
test' :: FooBar -> Bool
test' (Foo x) = (some logic)
test' _ = (the default value)
There is a neat concept called a "prism" that models this general concept -- extracting pieces of data from sum types -- elegantly. But they're... kind of hard to understand, and whether or not they can be considered "idiomatic" is pretty controversial.
You could use guards or pattern matching in the functions you are handing a FooBar as an argument.

Mandatory Maybes in the type system

I have something similar to the following
data A = A
{ id :: Integer
, foo :: Maybe String
, bar :: Maybe String
, baz :: Maybe String
}
This data is coming in to my service as JSON. This request is only considered valid when one or more of foo, bar, or baz are given. Is there a better way to express this within Haskell's type system?
Note: Unfortunately I am unable to make this separate requests. I'm just following a defined protocol.
http://hackage.haskell.org/package/these-0.4.2/docs/Data-These.html
import Data.These
data A = A
{ id :: Integer
, fooBarBaz :: These Foo (These Bar Baz)
}
type Foo = String
type Bar = String
type Baz = String
If it is not mandatory to have three separate fields with foo,bar and baz, I'd go with this, NonEmpty guarantees that there is at least one element, though there can of course be more.
import Data.List.NonEmpty
data Impression = Banner String | Video String | Native String
data A = A
{ id :: Integer
, fooBarBaz :: NonEmpty Impression
}
I would use a Map Field String with data Field = Foo | Bar | Baz (this can easily be replaced with String if needed, and then have:
data A = A
{ id :: Integer
, fields :: Map Field String
}
Now checking for the validity condition is as simple as:
isValid :: A -> Bool
isValid = not . Map.null . fields
Expanding on ʎǝɹɟɟɟǝſ's suggestion to use a map: there's also a type specifically for non-empty maps. (Note however that this sort of clashes with the more popular nonempty-list type from the semigroups library.)
import qualified Data.NonEmpty.Map as NEM
data Field = Foo | Bar | Baz
data A = A { id :: Integer
, fields :: NEM.T Field String
}
Consider giving one branch for each possible required field:
data A
= Foo
{ foo :: String
, barM, bazM :: Maybe String
}
| Bar
{ bar :: String
, fooM, barM :: Maybe String
}
| Baz
{ baz :: String
, fooM, barM :: Maybe String
}
It's a fair bit of boilerplate, but it's very direct and quite clear about what's required.

Is it possible to define a function in Haskell that has an input argument of two possible types?

For my own understanding, I want to define a function in Haskell that takes two arguments- either both Integers, or both Chars. It does some trivial examination of the arguments, like so:
foo 1 2 = 1
foo 2 1 = 0
foo 'a' 'b' = -1
foo _ _ = -10
This I know won't compile, because it doesn't know whether its args are of type Num or Char. But I can't make its arguments polymorphic, like:
foo :: a -> a -> Int
Because then we are saying it must be a Char (or Int) in the body.
Is it possible to do this in Haskell? I thought of maybe creating a custom type? Something like:
data Bar = Int | Char
foo :: Bar -> Bar -> Int
But I don't think this is valid either. In general, I'm confused about if there's a middle ground between a function in Haskell being either explicitly of ONE type, or polymorphic to a typeclass, prohibiting any usage of a specific type in the function body.
You can use the Either data type to store two different types. Something like this should work:
foo :: Either (Int, Int) (Char, Char) -> Int
foo (Right x) = 3
foo (Left y) = fst y
So, for it's Left data constructor you pass two Int to it and for it's Right constructor you pass two Char to it. Another way would be to define your own algebric data type like this:
data MyIntChar = MyInt (Int, Int) | MyChar (Char, Char) deriving (Show)
If you observe, then you can see that the above type is isomorphic to Either data type.
I'm not sure I would necessarily recommend using typeclasses for this, but they do make something like this possible at least.
class Foo a where
foo :: a -> a -> Int
instance Foo Int where
foo 1 2 = 1
foo 2 1 = 0
foo _ _ = -10
instance Foo Char where
foo 'a' 'b' = -1
foo _ _ = -10
You can do
type Bar = Either Int Char
foo :: Bar -> Bar -> Int
foo (Left 1) (Left 2) = 1
foo (Right 'a') (Right 'b') = -1
foo (Left 3) (Right 'q') = 42
foo _ _ = 10
and things like that - the Either data type is precisely for mixing two types together. You can roll your own similar type like
data Quux = AnInt Int | AChar Char | ThreeBools Bool Bool Bool
It's called an Algebraic Data Type.
(I struggle to think of circumstances when it's useful to mix specifically characters and integers together - mainly it's very helpful to know where your data is and what type it is.)
That said, I write algebraic data types a lot, but I give them meaningful names that represent actual things rather than just putting random stuff together because I don't like to be specific. Being very specific or completely general is useful. In between there are typeclasses like Eq. You can have a function with type Eq a => a -> [a] -> Bool which means it has type a -> [a] -> Bool for any type that has == defined, and I leave it open for people to use it for data types I never thought of as long as they define an equality function.

What is a better way to decode/encode binary little endian data in Haskell?

What is a best approach to get rid of a boilerplate code that serializes/deserializes binary data in Haskell, taking endianness into account? I.e., given this struct:
data Foobar = Foobar { foo :: Word16, bar :: Word32 }
And derived Data.Binary.Binary type class instance:
instance Binary Foobar where
get = do
foo <- get
bar <- get
return $ Foobar foo bar
decode stream :: Foobar treats the data as big endian.
Obvious way is to use getWord16le/getWord32le functions, but it involves lots of manual work (which could be automatically and nicely done by Template Haskell coupled with derive).
Perhaps, parametrized types are the solution?
How about defining little-endian newtypes for words?
newtype LWord16 = LWord16 { unLWord16 :: Word16 }
newtype LWord32 = LWord32 { unLWord32 :: Word32 }
instance Binary LWord16 where get = LWord16 <$> getWord16le
instance Binary LWord32 where get = LWord32 <$> getWord32le
Then deriving Binary for the definition
data Foobar = Foobar { foo :: LWord16, bar :: LWord32 }
should do the right thing.
You can define a typeclass for different Word types, such as:
class BinaryEndian a where
getEndian :: Get a
putEndian :: a -> Put
instance BinaryEndian Word16 where
getEndian = getWord16le
putEndian = putWord16le
etc.
That would make TH code perhaps a little easier to write.

Haskell record syntax and type classes

Suppose that I have two data types Foo and Bar. Foo has fields x and y. Bar has fields x and z. I want to be able to write a function that takes either a Foo or a Bar as a parameter, extracts the x value, performs some calculation on it, and then returns a new Foo or Bar with the x value set accordingly.
Here is one approach:
class HasX a where
getX :: a -> Int
setX :: a -> Int -> a
data Foo = Foo Int Int deriving Show
instance HasX Foo where
getX (Foo x _) = x
setX (Foo _ y) val = Foo val y
getY (Foo _ z) = z
setY (Foo x _) val = Foo x val
data Bar = Bar Int Int deriving Show
instance HasX Bar where
getX (Bar x _) = x
setX (Bar _ z) val = Bar val z
getZ (Bar _ z) = z
setZ (Bar x _) val = Bar x val
modifyX :: (HasX a) => a -> a
modifyX hasX = setX hasX $ getX hasX + 5
The problem is that all those getters and setters are painful to write, especially if I replace Foo and Bar with real-world data types that have lots of fields.
Haskell's record syntax gives a much nicer way of defining these records. But, if I try to define the records like this
data Foo = Foo {x :: Int, y :: Int} deriving Show
data Bar = Foo {x :: Int, z :: Int} deriving Show
I'll get an error saying that x is defined multiple times. And, I'm not seeing any way to make these part of a type class so that I can pass them to modifyX.
Is there a nice clean way of solving this problem, or am I stuck with defining my own getters and setters? Put another way, is there a way of connecting the functions created by record syntax up with type classes (both the getters and setters)?
EDIT
Here's the real problem I'm trying to solve. I'm writing a series of related programs that all use System.Console.GetOpt to parse their command-line options. There will be a lot of command-line options that are common across these programs, but some of the programs may have extra options. I'd like each program to be able to define a record containing all of its option values. I then start with a default record value that is then transformed through a StateT monad and GetOpt to get a final record reflecting the command-line arguments. For a single program, this approach works really well, but I'm trying to find a way to re-use code across all of the programs.
You want extensible records which, I gather, is one of the most talked about topics in Haskell. It appears that there is not currently much consensus on how to implement it.
In your case it seems like maybe instead of an ordinary record you could use a heterogeneous list like those implemented in HList.
Then again, it seems you only have two levels here: common and program. So maybe you should just define a common record type for the common options and a program-specific record type for each program, and use StateT on a tuple of those types. For the common stuff you can add aliases that compose fst with the common accessors so it's invisible to callers.
You could use code such as
data Foo = Foo { fooX :: Int, fooY :: Int } deriving (Show)
data Bar = Bar { barX :: Int, barZ :: Int } deriving (Show)
instance HasX Foo where
getX = fooX
setX r x' = r { fooX = x' }
instance HasX Bar where
getX = barX
setX r x' = r { barX = x' }
What are you modeling in your code? If we knew more about the problem, we could suggest something less awkward than this object-oriented design shoehorned into a functional language.
Seems to me like a job for generics. If you could tag your Int with different newtypes, then you would be able to write (with uniplate, module PlateData):
data Foo = Foo Something Another deriving (Data,Typeable)
data Bar = Bar Another Thing deriving (Data, Typerable)
data Opts = F Foo | B Bar
newtype Something = S Int
newtype Another = A Int
newtype Thing = T Int
getAnothers opts = [ x | A x <- universeBi opts ]
This would extract all Another's from anywhere inside the Opts.
Modification is possible as well.
If you make the types instances of Foldable you get a toList function that you can use as the basis of your accessor.
If Foldable doesn't by you anything, then maybe the right approach is to define the interface you want as a type class and figure out a good way to autogenerate the derived values.
Perhaps by deriving from doing
deriving(Data)
you could use gmap combinators to base your access off.

Resources