这是一个绝对的初学者Haskell问题。可能需要进行一些编辑。
给出以下代码:
import Data.Maybe
someFunction :: String b => Int -> Maybe b
someFunction x = Nothing
我收到错误:
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
我想明白为什么我会看到这个错误。
a Similar签名适用于:
import Data.Maybe
somethingElse :: Num b => Int -> Maybe b
somethingElse x = Nothing
Num和String之间的区别是什么? (可能是因为String不是类型类?)
我能否以与Num类似的方式为String创建速记? (可能是的?)
如果我遇到这种情况,如何才能找到正确的类型?
更新
为了说明我想要为String类型提供简写的原因:
somethingElse :: String -> String -> String -> String
somethingElse x s t = t ++ s ++ x
编译,但我更愿意写:
somethingElse :: ??? a => a -> a -> a -> a
somethingElse x s t = t ++ s ++ x
答案 0 :(得分:5)
在阅读了对@YellPika的回答的评论之后,抓住我之前所说的内容。如果要为String
定义较短类型的同义词,您只需要
-- Not that this serves any useful purpose.
type Str = String
然后您可以在类型注释中使用同义词:
someFunction :: Int -> Maybe Str
someFunction x = Nothing
但是,实际上,这是一个坏主意。每个人都知道String
代表[Char]
,因为它在标准库中。只有您知道同义词Str
代表String
。如果您关注长类型注释,可以使用Haskell的类型推断。
Num
是类型,而不是类型。 type class定义了为多种类型in an ad-hoc fashion提供的方法集合。主流语言中最接近的模拟是C ++标准库中的concept和原始STL的概念。 (但是,类型类是Haskell语言的本机结构,而C ++ / STL概念只存在于C ++程序员的头脑中。)
(留待这里仅供参考)
您可能正在寻找-XOverloadedStrings
扩展程序。这使得字符串文字的类型为IsString s => s
。
以下是ghci会话的示例:
> :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'
在Haskell源文件(* .hs)中,您可以通过在顶部添加来使用此扩展:
{-# LANGUAGE OverloadedStrings #-}
module What.Ever where
-- ...
注意:所有这些都假设您使用的是GHC。我还没有尝试过其他Haskell实现。
答案 1 :(得分:5)
该错误有点误导。字符串(定义为type String = [Char]
)没有类型参数,但您只给它一个(String b
)。
但是,只能在约束中指定类型类(即在=>
之前),因此无论您提供多少参数String
,您尝试编译的都将无法编译。
您想要做的只是someFunction :: Int -> Maybe String
。
好吧,如果你想要一个速记,那么我想你可以这样做:
type S = String
someFunction :: Int -> Maybe S
虽然我认为这会使代码混淆不清。
作为旁注:类型类不,用于为类型创建本地定义的缩写。
我只记得您可以使用类型相等约束来模拟缩写。
{-# LANGUAGE TypeFamilies #-} -- Or GADTs
somethingElse :: s ~ String => s -> s -> s -> s
somethingElse x y z = x ++ y ++ z
通过使用类型相等,“同义词”现在在本地定义,因此比定义type SomeOtherNameForStringThatIsShorterThan'String' = String
更难以阅读。
但我仍然建议只写出完整的类型。
答案 2 :(得分:1)
原帖要求String
的“简称”。但是,我对Num
示例所做的事情实际上是函数的抽象。你已经让你的第一个somethingElse
函数适用于其他类型的数字(双打,复合体等)!
在同样的意义上,您可以将Monoid
类型类用于第二个somethingElse
函数,如下所示:
import Data.Monoid
somethingElse :: Monoid a => a -> a -> a -> a
somethingElse x s t = t <> s <> x
所以你可以说
somethingElse "World!" ", " "Hello"
并获取
"Hello, World!"
<强>释强>
您要求String
的类型类。在Haskell中没有类似的东西,因为String
只是[Char]
的另一个名称。
即使haskell中的[]
不类型类。 Haskell中的类型类是一个帮助您提取具体数据类型的抽象行为的概念。但[]
是具体的数据类型(尽管它有1个类型参数)。
根据您的使用,您对[]
连接的能力很感兴趣。有一个类型类可以捕获这种行为。此类型类为Monoid
。其mappend
或<>
运算符与++
的{{1}}完全相同,但它也适用于其他[]
类型。例如,当与Monoid
一起使用时,Sum Int
会有效地总结其参数并为您提供总结果。
这就是您真正想要的:<>
类型类为Monoid
做正确的事情,并使您的上一个String
函数具有预期的类型签名形式。
但请记住:somethingElse
仅限Monoid
++
运算符,如果您需要其他内容,则需要其他抽象。