2
votes

This is an absolute beginner Haskell question. Probably needs a couple of edits.

Given the following code:

import Data.Maybe
someFunction :: String b => Int -> Maybe b
someFunction x = Nothing

I get the error:

Main.hs@2:18-2:26`String' is applied to too many type arguments
In the type signature for `someFunction':
  someFunction :: String b => Int -> Maybe b

I'd like to understand exactly why I see this error.

The a Similar signature works for:

import Data.Maybe
somethingElse :: Num b => Int -> Maybe b
somethingElse x = Nothing

What's the difference between Num and String that causes this? (probably because String is not a type class?)

Can I create a shorthand for String in a similar fashion to Num? (probably yes?)

How can I find the correct type class to use if I'm in such a situation?

UPDATE:

To illustrate the reason I want to have a shorthand for the String type:

somethingElse ::  String -> String -> String -> String
somethingElse x s t  =  t ++ s ++ x

This compiles, but I'd prefer to write:

somethingElse :: ??? a => a -> a -> a -> a
somethingElse x s t  =  t ++ s ++ x
3
Perhaps you are looking for -XOverloadedStrings? That makes string literals have type IsString s => s.pyon
I could be Eduardo, but I'm a little more clueless than that. I'll look into it and get more clues. Thanks for the pointer.iwein
I might miss something, but I think the problem is that Num is a parametric class (or typeclass) while String is a type ( or alias for the data type [Char]) that takes no type parameters.Nadir Sampaoli
@iwein That explains where you're coming from, but that's not what type classes are for. To get a shorter or more descriptive name, we use type synonyms, but String is already a synonym for [Char] and it's reasonably short. If you have so many String parameters that you feel the need to introduce a shorthand notation, you should probably do some refactoring instead.raymonad
There’s a question on the lack of a container-like common typeclass, with several good answers. That being said, there are e.g. Foldable and Traversable (as well as their monomorphized versions) that capture certain aspects of a container, at least when it comes to reading.Luc Danton

3 Answers

5
votes

Updated answer:

After reading your comment to @YellPika 's answer, scratch what I previously said. If you want to define a shorter type synonym for String, all you have to do is

-- Not that this serves any useful purpose.
type Str = String

Then you can use the synonym in type annotations:

someFunction :: Int -> Maybe Str
someFunction x = Nothing

But, really, this is a bad idea. Everyone knows that String stands for [Char], because it is in the standard library. Only you would know that your synonym Str stands for String. If you are concerned with long type annotations, you can use Haskell's type inference.

Num is a type class, not a type. A type class defines a collection of methods that be provided for multiple types in an ad-hoc fashion. The closest analog in a mainstream language would be the notion of concept in C++'s standard library and the original STL. (However, type classes are native constructs of the Haskell language, while C++/STL concepts only exist in the heads of C++ programmers.)


What I previously said:

(Left here just for reference)

You might be looking for the -XOverloadedStrings extension. That makes string literals have type IsString s => s.

Here is an example from a ghci session:

> :set -XOverloadedStrings
> import Data.String
> import Data.ByteString
> import Data.Text
> :t "a"
"a" :: IsString a => a
> :i IsString
class IsString a where
  fromString :: String -> a
    -- Defined in `Data.String'
instance IsString ByteString
  -- Defined in `Data.ByteString.Internal'
instance IsString Text -- Defined in `Data.Text'
instance IsString [Char] -- Defined in `Data.String'

In a Haskell source file (*.hs), you can use this extension by adding at the top:

{-# LANGUAGE OverloadedStrings #-}
module What.Ever where

-- ...

Note: All of this assumes you are using GHC. I have not tried other Haskell implementations.

5
votes

The error is somewhat misleading. String (defined as type String = [Char]) has no type parameters, but you're giving it one (String b).

However, only type classes can be specified in constraints (i.e. before the =>), so what you're attempting would fail to compiler regardless of how many arguments you gave String.

What (I think) you want to do is simply someFunction :: Int -> Maybe String.


Well, if you want a shorthand, then I suppose you can just do this:

type S = String

someFunction :: Int -> Maybe S

Although I think that obfuscates the code a bit.

As a side note: Type classes are not for creating locally defined shorthands for a type.


Addition:

I just remembered that you can emulate shorthands using type equality constraints.

{-# LANGUAGE TypeFamilies #-} -- Or GADTs

somethingElse :: s ~ String => s -> s -> s -> s
somethingElse x y z = x ++ y ++ z

By using type equalities, the "synonym" is now locally defined, and thus less confusing to read than defining type SomeOtherNameForStringThatIsShorterThan'String' = String.

But I would still recommend just writing out the full type.

1
votes

The original post asks for "short hand" of String. However, I thing what you have did for Num example is actually abstraction of functions. You have made your first somethingElse function works for other kind of numbers (doubles, complexes etc) as well!

In the same sense you can use Monoid type class for your second somethingElse function, as the following:

import Data.Monoid

somethingElse :: Monoid a => a -> a -> a -> a
somethingElse x s t = t <> s <> x

So you can say

somethingElse "World!" ", " "Hello"

and get

"Hello, World!"

Explaination

You were asking for a type class for String. There is no such thing like that in Haskell because String is just another name for [Char].

Even [] in haskell is NOT a type class. Type classes in Haskell is a concept that helps you extract abstract behaviors of concrete data types. But [] is a concrete data type (although it have 1 type parameter).

According to your use, you are interesting in the ability of [] of concatenating. There is a type class that capture this kind of behavior. This type class is Monoid. Its mappend or <> operator does exactly the same as ++ for [] but it can work for other Monoid types as well. For example, when use with Sum Int, <> effectively sums up its parameters and gives you the total result.

So this is what you actually want: the Monoid type class does the right thing for String, and makes your last somethingElse function have the expected form of type signature.

But keep in mind: Monoid caputures only ++ operator of List, if you need something else, you will need other abstractions.