# Type inference in Haskell v. Scala

Given the following code:

```
Prelude> let f x = if (x) then 55 else "foo"
```

Why is the compiler looking for `Num [Char]`

?

```
<interactive>:2:23:
No instance for (Num [Char]) arising from the literal `55'
In the expression: 55
In the expression: if (x) then 55 else "foo"
In an equation for `f': f x = if (x) then 55 else "foo"
```

However, in Scala it will find the smallest upper bound `55`

and `"foo"`

, which is `Any`

:

```
scala> def f(x: Boolean) = if (x) 55 else "foo"
f: (x: Boolean)Any
import scala.reflect.runtime.universe._
scala> lub( List[Type]( typeOf[Int], typeOf[String] ) )
res4: reflect.runtime.universe.Type = Any
```

What's the key difference between Haskell and Scala Type Inference?

source to share

You can add an instance for `Num [Char]`

in Haskell if you need it:

`{-# LANGUAGE FlexibleInstances #-} import Data.Function (on) import Data.Composition ((.:)) -- cabal install composition helper :: (Integer -> Integer -> Integer) -> (String -> String -> String) helper op = show .: on op read cast :: (Integer -> Integer) -> (String -> String) cast f = show . f . read instance Num [Char] where fromInteger = show (+) = helper (+) (-) = helper (-) (*) = helper (*) abs = cast abs signum = cast signum negate = cast negate`

where this is just one possible implementation. This will make your example compile:

`> let f x = if x then 55 else "foo" > f True "55" > f False "foo"`

Haskell has polymorphic numeric literals, so `55 :: Num a => a`

, and since both branches `if`

must return the same type, you force `a ~ [Char]`

with `else`

return return `"foo"`

. This results in a somewhat confusing error message, but it can be a very powerful feature. This means that any numeric literal can act as the type you need, and this is the same concept behind expansion `OverloadedStrings`

, allowing you to have polymorphic string literals instead of being used `pack`

wherever you need `Text`

or `ByteString`

.

Scala uses subtyping and has a common type for all values. This allows you to relax type safety on functions and literally return a `Any`

thing. Haskell has no subtypes at all, so the only way to unify these types (similar to finding a LUB) is to take advantage of the fact that numeric literals are polymorphic by constraint `Num`

, so `"foo"`

it needs to be implemented in order to compile `Num`

. In fact, if you included `OverloadedStrings`

`f`

it will just compile with the type

```
f :: (Data.String.IsString a, Num a) => Bool -> a
```

By default, there are no types that meet both constraints, but GHC will happily accept this as a valid feature.

source to share

This is because of how number literals are interpreted in Haskell.

```
λ> :type 412
412 :: Num a => a
```

What this does behind the scenes is calling the `Num`

class function `fromInteger`

to convert, `412`

or in your case, `55`

to any instance.

We can look at the class `Num`

like this:

```
λ :info Num
class Num a where
(+) :: a -> a -> a
(*) :: a -> a -> a
(-) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
```

So when you write `55`

and `"foo"`

, Haskell first understands that the return value must be of a type `[Char]`

because it `"foo" :: [Char]`

tries to find an instance `Num`

that matches that. Of course he fails.

Scala is a much less strongly typed language, and since it does not have class types in the same way as Haskell's, it can only be used to describe similar types `Any`

. I don’t think I need to explain why it’s not, because type errors are never fun.

If you want to return either `Int`

or `String`

, you can use `Either`

:

```
f :: Bool -> Either Int String
f b = if b then Left 55 else Right "foo"
```

source to share

If you're still a little confused, it helps to understand a little about how the back-end works.

In Haskell, a type class is a **dictionary of functions associated with a type** . Each type can only have one dictionary of functions for each type. When this happens, we say that it satisfies the associated constraints. So if you type `:t 5`

in GHCi it will tell you that type 5 is equal `Num a => a`

, in other words, there are many types that matter `5`

, and those types are the ones that have a `Num`

Dictionary. This is true because the dictionary `Num`

defines a function `fromInteger :: Num a => Integer -> a`

that takes a particular `5`

type `Integer`

and passes it on to that other type.

So he complains that he doesn't have a dictionary `Num`

defined for the type `String`

, and of course he doesn't, because people don't usually use strings as numbers. (Type `String`

is an alias for `[Char]`

.)

So when you write:

```
let f x = if x then 55 else "foo"
```

then this is what happens:

- Haskell is strongly typed, and
`if`

is an expression with a specific return value with a specific type. Both branches must be of the same type. - The GHC knows this and recognizes first that the type
`x`

is equal`x :: Bool`

(since it looks like an if-branch test, and Haskell's strong types do not allow implicit coercion), and that for`55 :: Num x => x`

now`"foo" :: String`

. - GHC now
**combines**those last two types. It does this by merging constraints separately from merging types, so it merges`x`

with`String`

to find out what's`x = String`

at the level of the level. - GHC extends result constraint to say what type
`Num String => String`

. - GHC is complaining because it doesn't know what the dictionary looks like
`Num`

for`String`

.

How do you solve this problem? The easiest way is to use a data structure `data Either x y = Left x | Right y`

that is built into Haskell:

```
let f x = if x then Left 55 else Right "foo"
```

The type of output is then `Num x => Either x String`

, which is perfectly normal and does not combine the two. **Caution** . Because of what's called the "monomorphism constraint", which is the default in GHC but not GHCi, unless you provide explicit type annotation that says otherwise, it `f`

can be reduced `Num a => Either a String`

to `Either Integer String`

:

```
Prelude> :set -XMonomorphismRestriction
Prelude> let f x = if x then Left 55 else Right "foo"
Prelude> :t f
f :: Num a => Bool -> Either a [Char]
Prelude> let f = \x -> if x then Left 55 else Right "foo"
Prelude> :t f
f :: Bool -> Either Integer [Char]
```

source to share