Two-level type hierarchy with Haskell - haskell

I want to model 4 kinds of directions in my application: right, left, up and down. However, I want to be able to have a function that takes only the horizontal ones for a variable and the vertical ones for other variable.
To solve this, I can have two types: HorizontalDirection and VerticalDirection:
data HorizontalDirection = RightDir | LeftDir
data VerticalDirection = UpDir | DownDir
foo :: HorizontalDirection -> VerticalDirection -> String
foo hDir vDir = "This works"
However, I also would like to be able to have a function that can take one type as well as the other, something like this:
bar :: Direction -> String
bar (HorizontalDirection _) = "Horizontal!"
bar (VerticalDirection _) = "Vertical!"
but this wouldn't work since HorizontalDirection and VerticalDirection aren't data constructors.
I know I can use Either and make it work, like this:
bar :: (Either HorizontalDirection VerticalDirection) -> String
bar (Left _) = "Horizontal!"
bar (Right _) = "Vertical!"
however, I wonder if I can do this without the Either type.
I also tried using typeclasses:
data HorizontalDirection = RightDir | LeftDir
data VerticalDirection = UpDir | DownDir
class Direction a
instance Direction HorizontalDirection
instance Direction VerticalDirection
baz :: Direction d => d -> String
baz RightDir = "Horizontal"
but that gives me the following compiler error:
Direction.hs:21:5: error:
• Couldn't match expected type ‘d’
with actual type ‘HorizontalDirection’
‘d’ is a rigid type variable bound by
the type signature for:
baz :: forall d. Direction d => d -> String
at Direction.hs:20:1-33
• In the pattern: RightDir
In an equation for ‘baz’: baz RightDir = "Horizontal"
• Relevant bindings include
baz :: d -> String (bound at Direction.hs:21:1)
Is my way of thinking totally wrong here? Or am I just missing something?

Instead of using Either you can declare a new data type with more meaningful names.
data Direction
= Horizontal HorizontalDirection
| Vertical VerticalDirection
bar :: Direction -> String
bar (Horizontal _) = "Horizontal!"
bar (Vertical _) = "Vertical!"

You are quite close, but you need to define the function in the class:
class Direction a where
baz :: a -> String
instance Direction HorizontalDirection where
baz _ = "Horizontal"
instance Direction VerticalDirection where
baz _ = "Vertical"
Note however that Haskell is statically typed, and the types are known at compile time.

Related

Trying to search for an element in a listed tuple that has a new datatype

I've created a new datatype Board:
data Board a = Grid [(Position, Maybe a)]
deriving (Eq, Show)
where Position is its own datatype:
data Position = NW | N | NE | W | M | E | SW | S | SE
deriving (Eq, Ord, Show)
Now I'm trying to create a function label, that takes a Position and Board and returns the label at the given position (wrapped using Just) or Nothing if the given position is empty.
I was thinking of implementing a new function Search to do this.
search :: (Eq a) => a -> [(a,b)] -> Maybe b
search _ [] = Nothing
search x ((a,b):xs) = if x == a then Just b else search x xs
But I don't know how to pass in the List [(a,b)] from my Board input. I tried:
label :: Position -> Board a -> Maybe a
label p b = Search p b
and got the error:
* Couldn't match expected type: [(Position, a)]
with actual type: Board a
* In the second argument of `lookup', namely `b'
In the expression: lookup p b
In an equation for `label': label p b = lookup p b
* Relevant bindings include
b :: Board a (bound at A6.hs:21:9)
label :: Position -> Board a -> Maybe a (bound at A6.hs:21:1)
Perhaps there's an easier way to go about this, but this is the only way I could think of.
(Aplet123 pointed out a mistake, since updated and updated the error produced)
You need to look into your data type under the wraps to find the actual datum there,
label :: Position -> Board a -> Maybe a
label p (Grid b) = search p b
-- ^^^^
Function names in Haskell must not be capitalized. That is reserved for types and data constructors.
The above will give you another type error but you'll be able to tweak it, I believe, to get it fixed. For starters, enter the definition without the type signature, to see what type is inferred for it.

List of a Type Classe instance

I've been playing around with Haskell type classes and I am facing a problem I hope someone could help me to solve. Consider that I come from a Swift background and "trying" to port some of protocol oriented knowledge to Haskell code.
Initially I declared a bunch of JSON parsers which had the same structure, just a different implementation:
data Candle = Candle {
mts :: Integer,
open :: Double,
close :: Double
}
data Bar = Bar {
mts :: Integer,
min :: Double,
max :: Double
}
Then I decided to create a "Class" that would define their basic operations:
class GenericData a where
dataName :: a -> String
dataIdentifier :: a -> Double
dataParsing :: a -> String -> Maybe a
dataEmptyInstance :: a
instance GenericData Candle where
dataName _ = "Candle"
dataIdentifier = fromInteger . mts
dataParsing _ = candleParsing
dataEmptyInstance = emptyCandle
instance GenericData Bar where
dataName _ = "Bar"
dataIdentifier = fromInteger . mts
dataParsing _ = barParsing
dataEmptyInstance = emptyBar
My first code smell was the need to include "a" when it was not needed (dataName or dataParsing) but then I proceded.
analyzeArguments :: GenericData a => [] -> [String] -> Maybe (a, [String])
analyzeArguments [] _ = Nothing
analyzeArguments _ [] = Nothing
analyzeArguments name data
| name == "Candles" = Just (head possibleCandidates, data)
| name == "Bar" = Just (last possibleRecordCandidates, data)
| otherwise = Nothing
possibleCandidates :: GenericData a => [a]
possibleCandidates = [emptyCandle, emptyBar]
Now, when I want to select if either instance should be selected to perform parsing, I always get the following error
• Couldn't match expected type ‘a’ with actual type ‘Candle’
‘a’ is a rigid type variable bound by
the type signature for:
possibleCandidates :: forall a. GenericData a => [a]
at src/GenericRecords.hs:42:29
My objective was to create a list of instances of GenericData because other functions depend on that being selected to execute the correct dataParser. I understand this has something to do with the type class checker, the * -> Constraint, but still not finding a way to solve this conflict. I have used several GHC language extensions but none has solved the problem.
You have a type signature:
possibleCandidates :: GenericData a => [a]
Which you might thing implies that you can put anything in that list as long as it is GenericData. But that is not the way Haskell's type system actually works. The value possibleCandidates can be a list of any type which has a GenericData class but every element of the list must be of the same type.
What the GHC error message is telling you (in its own special way) is that the first element of the list is a Candle so it thinks that the rest of the list should also be of type Candle but the second element is actually a Bar.
Now there are ways to make heterogeneous lists (and other collections) in Haskell, but it is almost never the right thing to do.
One typical solution to this problem is to just merge everything down into one sum data type:
data GenericData = GenericCandle Candle | GenericBar Bar
You could even forgo the step of indirection and just put the Candle and Bar data directly into the data structure.
Now instead f a class you just have a datatype and your class functions become normal functions:
dataName :: GenericData -> String
dataIdentifier :: GenericData -> Double
dataParsing :: GenericData -> String -> Maybe a
dataEmptyInstance :: String -> GenericData
There are some other more complex ways to make this work, but if a sum data type fits the bill, use it. It is very common for parsers in Haskell to have a large sum data type (usually also recursive) as their result. Take a look at the Value type in Aeson the standard JSON library for an example.

data type with a default field and that needs a function that works with it

Say, I have a data type
data FooBar a = Foo String Char [a]
| Bar String Int [a]
I need to create values of this type and give empty list as the second field:
Foo "hello" 'a' []
or
Bar "world" 1 []
1) I do this everywhere in my code and I think it would be nice if I could omit the empty list part somehow and have the empty list assigned implicitly. Is this possible? Something similar to default function arguments in other languages.
2) Because of this [] "default" value, I often need to have a partial constructor application that results in a function that takes the first two values:
mkFoo x y = Foo x y []
mkBar x y = Bar x y []
Is there a "better" (more idiomatic, etc) way to do it? to avoid defining new functions?
3) I need a way to add things to the list:
add (Foo u v xs) x = Foo u v (x:xs)
add (Bar u v xs) x = Bar u v (x:xs)
Is this how it is done idiomatically? Just a general purpose function?
As you see I am a beginner, so maybe these questions make little sense. Hope not.
I'll address your questions one by one.
Default arguments do not exist in Haskell. They are simply not worth the added complexity and loss of compositionally. Being a functional language, you do a lot more function manipulation in Haskell, so funkiness like default arguments would be tough to handle.
One thing I didn't realize when I started Haskell is that data constructors are functions just like everything else. In your example,
Foo :: String -> Char -> [a] -> FooBar a
Thus you can write functions for filling in various arguments of other functions, and then those functions will work with Foo or Bar or whatever.
fill1 :: a -> (a -> b) -> b
fill1 a f = f a
--Note that fill1 = flip ($)
fill2 :: b -> (a -> b -> c) -> (a -> c)
--Equivalently, fill2 :: b -> (a -> b -> c) -> a -> c
fill2 b f = \a -> f a b
fill3 :: c -> (a -> b -> c -> d) -> (a -> b -> d)
fill3 c f = \a b -> f a b c
fill3Empty :: (a -> b -> [c] -> d) -> (a -> b -> d)
fill3Empty f = fill3 [] f
--Now, we can write
> fill3Empty Foo x y
Foo x y []
The lens package provides elegant solutions to questions like this. However, you can tell at a glance that this package is enormously complicated. Here is the net result of how you would call the lens package:
_list :: Lens (FooBar a) (FooBar b) [a] [b]
_list = lens getter setter
where getter (Foo _ _ as) = as
getter (Bar _ _ as) = as
setter (Foo s c _) bs = Foo s c bs
setter (Bar s i _) bs = Bar s i bs
Now we can do
> over _list (3:) (Foo "ab" 'c' [2,1])
Foo "ab" 'c' [3,2,1]
Some explanation: the lens function produces a Lens type when given a getter and a setter for some type. Lens s t a b is a type that says "s holds an a and t holds a b. Thus, if you give me a function a -> b, I can give you a function s -> t". That is exactly what over does: you provide it a lens and a function (in our case, (3:) was a function that adds 3 to the front of a List) and it applies the function "where the lens indicates". This is very similar to a functor, however, we have significantly more freedom (in this example, the functor instance would be obligated to change every element of the lists, not operate on the lists themselves).
Note that our new _list lens is very generic: it works equally well over Foo and Bar and the lens package provides many functions other than over for doing magical things.
The idiomatic thing is to take those parameters of a function or constructor that you commonly want to partially apply, and move them toward the beginning:
data FooBar a = Foo [a] String Char
| Bar [a] String Int
foo :: String -> Char -> FooBar a
foo = Foo []
bar :: String -> Int -> FooBar a
bar = Bar []
Similarly, reordering the parameters to add lets you partially apply add to get functions of type FooBar a -> FooBar a, which can be easily composed:
add :: a -> FooBar a -> FooBar a
add x (Foo xs u v) = Foo (x:xs) u v
add123 :: FooBar Int -> FooBar Int
add123 = add 1 . add 2 . add 3
add123 (foo "bar" 42) == Foo [1, 2, 3] "bar" 42
(2) and (3) are perfectly normal and idiomatic ways of doing such things. About (2) in particular, one expression you will occasionally hear is "smart constructor". That just means a function like your mkFoo/mkBar that produces a FooBar a (or a Maybe (FooBar a) etc.) with some extra logic to ensure only reasonable values can be constructed.
Here are some additional tricks that might (or might not!) make sense, depending on what you are trying to do with FooBar.
If you use Foo values and Barvalues in similar ways most of the time (i.e. the difference between having the Char field and the Int one is a minor detail), it makes sense to factor out the similarities and use a single constructor:
data FooBar a = FooBar String FooBarTag [a]
data FooBarTag = Foo Char | Bar Int
Beyond avoiding case analysis when you don't care about the FooBarTag, that allows you to safely use record syntax (records and types with multiple constructors do not mix well).
data FooBar a = FooBar
{ fooBarName :: String
, fooBarTag :: FooBarTag
, fooBarList :: [a]
}
Records allow you to use the fields without having to pattern match the whole thing.
If there are sensible defaults for all fields in a FooBar, you can go one step beyond mkFoo-like constructors and define a default value.
defaultFooBar :: FooBar a
defaultFooBar = FooBar
{ fooBarName = ""
, fooBarTag = Bar 0
, fooBarList = []
}
You don't need records to use a default, but they allow overriding default fields conveniently.
myFooBar = defaultFooBar
{ fooBarTag = Foo 'x'
}
If you ever get tired of typing long names for the defaults over and over, consider the data-default package:
instance Default (FooBar a) where
def = defaultFooBar
myFooBar = def { fooBarTag = Foo 'x' }
Do note that a significant number of people do not like the Default class, and not without reason. Still, for types which are very specific to your application (e.g. configuration settings) Default is perfectly fine IMO.
Finally, updating record fields can be messy. If you end up annoyed by that, you will find lens very useful. Note that it is a big library, and it might be a little overwhelming to a beginner, so take a deep breath beforehand. Here is a small sample:
{-# LANGUAGE TemplateHaskell #-} -- At the top of the file. Needed for makeLenses.
import Control.Lens
-- Note the underscores.
-- If you are going to use lenses, it is sensible not to export the field names.
data FooBar a = FooBar
{ _fooBarName :: String
, _fooBarTag :: FooBarTag
, _fooBarList :: [a]
}
makeLenses ''FooBar -- Defines lenses for the fields automatically.
defaultFooBar :: FooBar a
defaultFooBar = FooBar
{ _fooBarName = ""
, _fooBarTag = Bar 0
, _fooBarList = []
}
-- Using a lens (fooBarTag) to set a field without record syntax.
-- Note the lack of underscores in the name of the lens.
myFooBar = set fooBarTag (Foo 'x') defaultFooBar
-- Using a lens to access a field.
myTag = view fooBarTag myFooBar -- Results in Foo 'x'
-- Using a lens (fooBarList) to modify a field.
add :: a -> FooBar a -> FooBar a
add x fb = over fooBarList (x :) fb
-- set, view and over have operator equivalents, (.~). (^.) and (%~) respectively.
-- Note that (^.) is flipped with respect to view.
Here is a gentle introduction to lens which focuses on aspects I have not demonstrated here, specially in how nicely lenses can be composed.

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.

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