Overloading a function with a data type in Haskell - haskell

If I've declared a data type thus:
data ExampleType = TypeA (Int, Int) | TypeB (Int, Int, Int)
How can I declare a function that takes either TypeA or TypeB and performs different operations on that basis? My current attempt is:
exampleFunction :: ExampleType -> Int
exampleFunction (TypeA(firstInt, secondInt)) = --Fn body
exampleFunction (TypeB(firstInt, secondInt, thirdInt)) = --Fn body
But I'm getting a Duplicate type signatures error, so I'm clearly missing something.

Works for me:
data ExampleType = TypeA (Int, Int) | TypeB (Int, Int, Int)
exampleFunction :: ExampleType -> Int
exampleFunction (TypeA (a,b)) = a + b
exampleFunction (TypeB (a,b,c)) = a + c + c
main = print $ exampleFunction (TypeA (2,3))
http://ideone.com/jsIBVF
Note that you typically wouldn't use tuples as components of your type, as this makes it quite hard to get to the data. If you have not a very good reason, simply use
data ExampleType = TypeA Int Int | TypeB Int Int Int

Your code should not cause such an error. However there some things wrong with your question. First the use of a tuple is unsusual for a Product type (TypeA (Int, Int)). Instead you would just declare TypeA as a data constructor that takes two arguments of type Int instead of one of type (Int, Int). Furthermore TypeA and TypeB are not two different types but two different data constructors of the same sum type ExampleType. To reflect that I renamed them to DataA and DataB in the below code.
data ExampleType = DataA Int Int | DataB Int Int Int
exampleFunction :: ExampleType -> Int
exampleFunction (DataA x y) = x + y
exampleFunction (DataB x y z) = x + y + z

Related

Strict type alias in Haskell

Suppose I have a recursive function taking 3 integers, each having a different meaning, e.g.
func :: Int -> Int -> Int -> SomeType1 -> SomeType2
What I want is to prevent myself from mistyping the order of the arguments like this (somewhere in the func implementation):
func a b c t = f b a c ( someProcessing t )
The easiest way I've come up with is to define type aliases like
type FuncFirstArg = Int
type FuncSecondArg = Int
type FuncThirdArg = Int
And change func signature:
func :: FuncFirstArg -> FuncSecondArg -> FuncThirdArg -> SomeType1 -> SomeType2
But it seems like this approach doesn't work as I intended. Why does Haskell still allow me to pass FuncSecondArg as a first argument and so on. Is there a way to do what I want without declaring datatypes?
type in Haskell is a rename of an existing type. Just like String and [Char] are fully exchangeable, so are FuncFirstArg and Int, and by transition FuncSecondArg as well.
The most normal solution is to use a newtype which was introduced exactly for the purpose of what you try to achieve. For convenience, it is good to declare it as a record:
newtype FuncFirstArg = FuncFirstArg {unFuncFirstArg :: Int}
Note that newtype is entirely reduced during compilation time, so it has no overhead on the runtime.
However, if you have many arguments like in your example, a common strategy is to create a dedicated type for all of the parameters supplied to the function:
data FuncArgs = FuncArgs
{ funcA :: Int
, funcB :: Int
, funcC :: Int
, funcT :: Sometype1
}
f :: FuncArgs -> Sometype2
Yes, it has some bad impact on currying and partial application, but in many cases you can deal with it by providing predefined argument packs or even uncurry the function:
defaultArgs :: Sometype1 -> FuncArgs
defaultArgs t = FuncArgs {a = 0, b = 0, c = 0, t = t}
fUnc :: Int -> Int -> Int -> SomeType1 -> SomeType2
fUnc a b c t = f $ FuncArgs a b c t
Conclusion
For the typechecker to distinguish types, the types have to be actually different. You can't skip defining new types, therefore.

Encode Custom Data Type to Lazy Byte String

when you want to convert a custom type into bytestring you would do following:
data Foo = Foo {value1 :: Int}
instance Binary Foo where
get =liftM Foo get
put b = put (value1 b)
and if you have a type with multiple viable values as such:
data Foo2 = Foo2A Int | Foo2B Int
instance Binary Foo2 where
get = do flag <- getWord8
case flag of
0 -> fmap Foo2A get
1 -> fmap Foo2B get
put (Foo2A i) = do put (0 :: Word8)
put i
put (Foo2B i) = do put (1 :: Word8)
put i
but if you have a type as such (following...) how would I do this?:
data Foo3 = Foo3A Int | Foo3B
instance Binary Foo3 where
get = do flag <- getWord8
case flag of
0 -> fmap Foo3A get
1 -> ....????? Foo3B has no value - only Data Constructor
put (Foo3A i) = do put (0 :: Word8)
put i
put (Foo3B) = put (1 :: Word8)
You can also derive these instances:
newtype Foo = Foo {value1 :: Int}
deriving newtype Binary
data Foo2 = Foo2A Int | Foo2B Int
deriving stock Generic
deriving anyclass Binary
data Foo3 = Foo3A Int | Foo3B
deriving stock Generic
deriving anyclass Binary
To match what you wrote for put, you want pure Foo3B there in get.

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.

Create a haskell constructor for a new data type that takes in a function

I want to create a new data type that can take in a function.
I know this works:
foo :: (Int -> Int -> Int)->Int->Int->Int
foo func x y = (func x y) + 100
so you can do this:
foo (+) 5 8 --output is 113
Now I want to do the same thing but to a custom data type like this:
data Bar = Bar (Int Int Int) Int Int --This does not compile
so I can use it like this:
doCalc :: Bar -> Int
doCalc (Bar func x y) = (func x y) + 100
My question is how do I declare the constructor in my data type to do this?
Note that the first argument of foo is of type (Int -> Int -> Int) - the type of a function that takes two Ints and return another one. (Int Int Int) is not a legal Haskell type (since Int is a concrete type and not a type constructor, like Maybe).
Try:
data Bar = Bar (Int -> Int -> Int) Int Int
Your doCalc function is correct and will work with the new version.

Functional dependency: Two types determining third type

Why doesn't this code work:
class Foo a b c | a b -> c where
foo :: a -> b -> c
instance Foo Int Int Int where
foo a b = a + b
ghci > foo 4 4 -- This produces run time error
And by using functional dependency, why the following code produces compile time error:
instance Foo Float Float Int where
foo a b = a + b
I know that the above instance is an crazy example, but isn't the aim of functional dependency to help the type checker in resolving these issues ?
Actually it did resolve the ambiguity. The problem is that 4 :: Num a => a so GHC can't decide that you want to use foo :: Int -> Int -> Int. Now if instead you did
foo (4 :: Int) (4 :: Int)
> 8
Since now it is clear which instance we want to use. To make this clearer, suppose we had
class Foo a b c | a -> b, a -> c where
...
Now we could do
foo (4 :: Int) 4
> 8
since once GHC has filled in all the type variables not on the right side of an ->, it can fill in the rest.
instance Foo Float Float Int where
foo a b = a + b
This is a error even without the functional dependency. If a and b are Float, then a + b is a Float, not an Int.

Resources