Functional dependency: Two types determining third type - haskell

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.

Related

Haskell defined types

Studying Haskell first principles. Absolute beginner in Haskell.
If:
data A
data B
func :: A -> B
func = undefined
What would the actual function be? Worked though load of exercises with great result (also thanks to you) but again I am stuck. Does A -> B indicate two different types like 'String' -> 'Char'? Just trying to wrap my head around it.
No, (concrete) types start with an Uppercase. So A -> B means the types A and B you have defined (well not defined here) with your data A = ... expressions, like for instance:
data A = Foo | Bar Int | Qux String A
In case the signature contains an identifier with a lowercase, it is a type variable. For instance foo :: a -> b, means a and b can be substuted by any type. So foo is a function that can be A -> B, but also A -> Int, Char -> B, and Char -> Int.
You can also add type constraints to the signature to restrict the types for which for instance a and b can be used. Like foo :: (Show a, Num b) => a -> b restricts a and b, such that there should exist an instance Show a and instance Num b for the types a and b such that foo is defined over these types.
Thanks Willem, Chepner. Your answers helped me out to conjure up:
data A
data B
funcAJ :: A -> B
funcAJ a = a
where a = b
b = undefined
This typechecks as funcAJ :: A -> B, which I understand. Thanks so much!

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

Building data with logic

I have a data type like this:
data FooBar =
FooBar { foo :: Double
, bar :: Double
, ter :: Double
}
-- hypothetical builder with some random logic
mkFooBar :: Double -> Double -> FooBar
mkFooBar a b
| a < 5 = FooBar a b (a + b)
| a > 100 = FooBar a b (a * b)
| otherwise = FooBar (a ^ 2) (b ^ 2) ((a + b) ^2)
and some predefined values used around the program like:
fBLess5 = mkFooBar 1 200
fBMore100 = mkFooBar 200 200
fBSquared = mkFooBar 50 200
-- and so on
Is it ok building predefined values like that in Haskell? If fBLess5 is used N-times around the program, it will be built N-times if it is written in that way?
This will work. By binding the value to a name, you ensure that it is only evaluated (at most) once and then shared, no matter how often you use it.
(There is an exception, though:
foo :: (Num a) => a
foo = 42
This apparent constant is polymorphic and will be recomputed at each use (it's really fromInteger (42 :: Integer)). But that doesn't apply to your code, which is all monomorphic.)

MultiParamTypeClasses, FunctionalDependencies, and calling ambiguous functions

With functional dependencies, I can declare the Foo class:
class Foo a b c | a -> b where
foo1 :: a -> b -> c
foo2 :: a -> c
and when I call foo2, everything works fine. The compiler knows which instance to use because of the dependency.
But if I remove the dependency to create Foo':
class Foo' a b c where
foo1' :: a -> b -> c
foo2' :: a -> c
everything still compiles fine, but now whenever I try to call foo2' GHC throws an error about not being able to resolve which instance to use because b is ambiguous.
Is it ever possible to call foo2' without error? If so, how? If not, why doesn't it generate a compilation error?
It is impossible to call foo2' in this context, because, as Daniel Fischer says, there is no way to determine which instance to use. For example, if you had:
instance Foo' Int Int Int where
foo2' x = x
instance Foo' Int Bool Int where
foo2' x = x + 1
Both of these foo2's have the same type signature, so there is no way to determine which one to call.
The usual way around this problem is to use a proxy:
data Proxy a = Proxy
class Foo'' a b c = where
foo2'' :: Proxy b -> a -> c
Which you use like so to select which instance:
foo'' (Proxy :: Proxy Bool) 42

Problems with printf and ambiguous type variables

I have a little ambiguous type variable problem. I love haskell but this is really what I still fail to handle.
The problem is very easy and involves printf from Text.Printf. Since the problem is very general I'll just but in some sample code:
program = do
d <- addd 4 8
printf "%d" d
addd x y = return (x+y)
Of course printf is imported. The compiler then gives me an, obvious, ambiguous type variable error between Num and PrintfArg. I just don't know where to fit in the right type signature.
There are a few places you could put a type signature. Firstly, addd has most general type of (and the most general type is (almost always) what GHC infers when you leave off the signature):
addd :: (Monad m, Num a) => a -> a -> m a
You could restrict this to only work on a certain type by giving addd an explicit type signature, so that it isn't at all polymorphic in the arguments, e.g.:
addd :: Monad m => Int -> Int -> m Int
-- or,
addd :: Monad m => Integer -> Integer -> m Integer
Or, you could inform GHC of the input type when you call addd, e.g.:
d <- addd 4 (8 :: Integer)
and then the type inference will infer that 4 and d are both Integers.
Lastly, you can give d a type. Either when you use it (if you use d multiple times, you only need a single annotation), like so:
printf "%d" (d :: Integer)
Or when you set it (requires the GHC extension ScopedTypeVariables):
{-# LANGUAGE ScopedTypeVariables #-}
[...]
add = do
(d :: Integer) <- addd 4 8
I will try to explain what is wrong with your program.
Try giving explicit type signature, it helps compiler to infer types and also you to understand your program better.
addd is a pure function so don't use return.
return in not what you expect coming from an imperative background.
why do you need printf after all, use print or putStrLn if you want to output to console. Use show if you want to convert a type (whose show instance is defined) to string.
Here is your corrected program anyways
import Text.Printf
program :: String
program = do
let d = addd 4 8
printf "%d" d
addd :: Int -> Int -> Int
addd x y = x+y
You can write it just using print as
program :: IO ()
program = do
print $ addd 4 8
addd :: Int -> Int -> Int
addd x y = x+y
Try reading some introductory material on Haskell

Resources