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

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.

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.

Call a function inside a class without declaring an instance

I want to create a function in Haskell that does different things depending the data type it is given. I thought classes should do what I want, but now I ran into a problem. What I would like to be able to do is something similar to:
let x1 = myFunction :: MyInstance1
let x2 = myFunction :: MyInstance2
and it does different things depending on the given instance.
My current approach is
class MyClass a where
create :: Int -> a
doSomething :: a -> [Int]
myFunction :: [Int]
myFunction = doSomething $ create 4
instance MyClass MyInstance1 where
-- implementation of create and doSomething
instance MyClass MyInstance2 where
-- implementation of create and doSomething
However, the compiler tells me "The type variable a0 is ambiguous in the ambiguity check for 'myFunction'" and from what I've been reading this is related to the compiler not knowing what instance of 'doSomething' to call.
So is there a way to call 'doSomething' in a "generic" way and enforce the data type later? Or do I need an entirely different approach for my problem?
--- EDIT ---
So I applied chi's answer to my problem, but it does not solve it completely yet. Here's my code
{-# LANGUAGE AllowAmbiguousTypes #-}
class C a where
myFunction :: Int
create :: Int -> a
doSomething :: a -> Int
-- anotherFunction :: Int -> Int
-- anotherFunction x = doSomething $ create 4
instance C Int where
myFunction = 1
create x = 2 * x
doSomething x = x + 4
instance C Bool where
myFunction = 2
create x = True
doSomething x = if x then 42 else 24
This compiles and I in the prompt
create # Bool 4
create # Int 4
returns the expected results. However, anotherFunction does not compile properly giving the error message
Test.hs:8:23: error:
• Could not deduce (C a0) arising from a use of ‘doSomething’
from the context: C a
bound by the class declaration for ‘C’ at Test.hs:(3,1)-(8,44)
The type variable ‘a0’ is ambiguous
These potential instances exist:
instance C Bool -- Defined at Test.hs:15:10
instance C Int -- Defined at Test.hs:10:10
• In the expression: doSomething $ create 4
In an equation for ‘anotherFunction’:
anotherFunction x = doSomething $ create 4
Failed, modules loaded: none.
Is it simply not possible to use doSomething in this context? My idea is to implement the function in the same manner for all instances and then write
anotherFunction # Bool 4
anotherFunction # Int 6
You need a couple of extensions to do that, but it is doable. Here's a GHCi session showing that:
> :set -XAllowAmbiguousTypes
> class C a where myFunction :: Int
> instance C Int where myFunction = 1
> instance C Bool where myFunction = 2
> :set -XTypeApplications
> myFunction # Int
1
> myFunction # Bool
2
An "old" solution would be to add a proxy argument
class C a where myFunction :: proxy a -> Int
but hopefully this will fade out of style in a few years -- I find passing types explicitly clearer than passing proxies.
Full code, with another example:
{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables #-}
class C a where
myFunction :: Int
create :: Int -> a
doSomething :: a -> Int
anotherFunction :: Int -> Int
anotherFunction x = doSomething $ create # a 4
instance C Int where
myFunction = 1
create x = 2 * x
doSomething x = x + 4
instance C Bool where
myFunction = 2
create x = True
doSomething x = if x then 42 else 24
Tests:
> :set -XTypeApplications
> anotherFunction # Bool 4
42
> anotherFunction # Int 6
12

Overloading a function with a data type in 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

Number of arguments in Haskell code and type is different, why?

Can anybody explain the code below, what it does step by step, please. I know it is defining a function and its inputs, but what does (+) do, and why are there three Ints in plus and four Ints in plusplus's type, while it seems like there are only 3 arguments in plusplus's code?
plus :: Int -> Int -> Int
plus = (+)
plusPlus :: Int -> Int -> Int -> Int
plusPlus a b c = a + b + c
+ is the addition operator. Putting an operator in parentheses, like (+), refers to the addition function itself, as opposed to using + to add two numbers right on the spot. Basically, this:
plus = (+)
is equivalent to:
plus a b = a + b
Either way, it is defining plus to be a synonym for +.
In Haskell, -> is used to separate the types of the arguments, as well as the return value. So,
plus :: Int -> Int -> Int
is a function which takes two Ints and returns an Int.
plusPlus :: Int -> Int -> Int -> Int
is a function which takes three Ints and returns an Int.
The reason why the syntax is the same for the arguments and the return value is due to currying.
To be really pedantic,
plus :: Int -> Int -> Int -- ~ Int -> (Int -> Int)
is a function which takes an Int, and returns a function which takes an Int and returns an Int.
plusPlus :: Int -> Int -> Int -> Int -- ~ Int -> (Int -> (Int -> Int))
is a function which takes an Int, and returns a function which takes an Int, and returns a function which takes an Int and returns an Int.
In practice, it's convenient to speak of Haskell functions as taking multiple arguments. But technically, Haskell functions always take one argument. The argument type is on the left side of ->, and the return type is on the right side of ->, but the return type might itself be another function.

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.

Resources