Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I use String as a type class?

Tags:

haskell

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
like image 942
iwein Avatar asked May 22 '26 16:05

iwein


2 Answers

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.

like image 97
pyon Avatar answered May 25 '26 21:05

pyon


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.

like image 37
YellPika Avatar answered May 25 '26 22:05

YellPika