87

How to I define the equivalent of this function (taken from learnyouahaskell) inside GHCi?

import Data.List  

numUniques :: (Eq a) => [a] -> Int  
numUniques = length . nub  

Without the type declaration, GHCi accepts the function definition, but it ends up with an unhelpful type:

Prelude Data.List> import Data.List 
Prelude Data.List> let numUniques' = length . nub
Prelude Data.List> :t numUniques'
numUniques' :: [()] -> Int

The resulting function only accepts a list of units as a parameter.

Is there a way provide type declarations in GHCi? Or is there another way to define functions like these which doesn't require type declarations?

I saw no obvious clues in the GHCi guide, and experimented with expressions like the following (to no avail):

> let numUniques' = ((length . nub) :: (Eq a) => [a] -> Int)
> :t numUniques'
numUniques' :: [()] -> Int
mattbh
  • 5,230
  • 2
  • 27
  • 27

3 Answers3

104

Is there a way provide type declarations in GHCi?

let numUniques' :: (Eq a) => [a] -> Int; numUniques' = length . nub

Or is there another way to define functions like these which doesn't require type declarations?

If you turn off the monomorphism restriction with -XNoMonomorphismRestriction, it will infer the right type.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • 3
    I'm not yet there with the monomorphism, but generally this answer pointed me to using semicolons to group together definitions in GHCi - tutorials are written like in a .hs file, which gives many different problems when tried in GHCi (functions lacks binding etc.). – Tomasz Gandor Oct 27 '14 at 14:14
  • It's worth noting that `-XNoMonomorphismRestriction` is enabled by default for GHCi since 7.8.1: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#monomorphism – N. Shead Mar 12 '20 at 04:25
13

Note that you can also avoid the monomorphism restriction simply by adding "points" (i.e. explicit variables) back to your expression. So this also gives the correct type:

let numUniques x = length . nub $ x

sclv
  • 38,665
  • 7
  • 99
  • 204
10

The GHC User's Guide shows two additional ways to achieve this. This subsection introduces the :{ ... :} construct, which can be used as follows:

> :{
| numUniques :: (Eq a) => [a] -> Int
| numUniques = length . nub
| :}

Alternatively, you can enable multiline mode:

> :set +m
> let
| numUniques :: (Eq a) => [a] -> Int
| numUniques = length . nub
| 
Reinier Torenbeek
  • 16,669
  • 7
  • 46
  • 69