Reputation: 26161
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
Upvotes: 2
Views: 398
Reputation: 10436
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.
Upvotes: 1
Reputation: 2902
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.
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.
Upvotes: 5
Reputation: 19752
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.)
(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.
Upvotes: 5