我不清楚如何在haskell中编写函数签名,尤其是使用Maybe.考虑:
f :: Maybe a -> Maybe a
f = \a -> a
main = print (f (Just 5))
Run Code Online (Sandbox Code Playgroud)
这有效,但为什么函数签名不能这样呢?
f :: Maybe -> Maybe
Run Code Online (Sandbox Code Playgroud)
因为f只需要一个Maybe类型并返回一个Maybe类型.
相关:如果我想让Maybe类型更具体并且是a Maybe Int,为什么这不起作用?
f :: Maybe Int a -> Maybe Int a
f = \a -> a
main = print (f (Just (Int 5)))
Run Code Online (Sandbox Code Playgroud)
(我正在运行所有代码runhaskell test.hs)
luq*_*qui 10
好像你对类型变量感到困惑.首先,在
f :: Maybe a -> Maybe a
f = \a -> a
Run Code Online (Sandbox Code Playgroud)
的a的第一行有什么做的a的第二行,我们可以这样写:
f :: Maybe a -> Maybe a
f = \x -> x
Run Code Online (Sandbox Code Playgroud)
甚至
f :: Maybe foo -> Maybe foo
f = \bar -> bar
Run Code Online (Sandbox Code Playgroud)
这a是代表类型的变量.所以f这里声明f一次有很多类型:
f :: Maybe Int -> Maybe Int
f :: Maybe String -> Maybe String
f :: Maybe (Maybe Bool) -> Maybe (Maybe Bool)
...
Run Code Online (Sandbox Code Playgroud)
等等.正如我怀疑你所想的那样,这不是一些"标记"的论点.两者a相同的事实意味着参数类型必须是相同的结果类型.如果我们说过f :: Maybe a -> Maybe b我们会得到这个家庭:
f :: Maybe Int -> Maybe Bool
f :: Maybe String -> Maybe String
f :: Maybe (Maybe Bool) -> Maybe Int
...
Run Code Online (Sandbox Code Playgroud)
也就是说,a并且b现在可以代表不同的类型,但参数和结果还是要Maybe.
你不能说的原因
f :: Maybe -> Maybe
Run Code Online (Sandbox Code Playgroud)
因为Maybe它不是一个类型 - 它是一个类型构造函数.如果你给它一个类型,它会给你一个类型.所以Maybe Int并且Maybe String是类型,并且通常Maybe a是类型,只要a是类型.
Maybe Int a(已解析(Maybe Int) a)没有意义,因为Maybe Int它不是一个类型构造函数 - 它不再接受任何参数.
推荐阅读:LYAH的类型和类型.
Maybe是一个类型构造函数,本质上是一个类型级函数.它需要一个类型(例如Int)并返回一个类型(例如Maybe Int).该类型的"类型"被称为种:种有值的类型,比如Int,被称为*.采用一个参数的类型构造函数的类型是* -> *.你可以使用:kind/ :k命令在GHCi中看到这个:
> :k Int
Int :: *
> :k Maybe
Maybe :: * -> *
> :k Either
Either :: * -> * -> *
Run Code Online (Sandbox Code Playgroud)
在签名中Maybe a -> Maybe a,a是一个类型变量,在调用函数时会被特定类型替换.(隐含地,这意味着forall a. Maybe a -> Maybe a,如果您启用诸如ExplicitForall或之类的扩展,您可以自己编写ScopedTypeVariables.)
因此,如果你调用f :: Maybe a -> Maybe aa Maybe Int,那么在该调用站点上f有类型Maybe Int -> Maybe Int,因为a已经实例化了Int.
编译器拒绝,Maybe Int a因为您Maybe只提供两个参数,只接受一个参数.(这a不是参数的名称,而是类型的参数.)同样,它拒绝Maybe -> Maybe因为你没有给出Maybe参数,所以你试图将两种类型的类型* -> *传递给函数箭头构造函数(->),它接受参数善良的*:
> :k (->)
(->) :: * -> * -> *
Run Code Online (Sandbox Code Playgroud)
顺便说一句,有可能写出类似的内容Maybe -> Maybe并将其展开Maybe a -> Maybe a,这有时会很有用,但几乎肯定不是你现在想做的事情.
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
type (~>) f g = forall a. f a -> g a
f :: Maybe ~> Maybe
f x = x
Run Code Online (Sandbox Code Playgroud)
在这里,类型同义词Maybe ~> Maybe扩展为forall a. Maybe a -> Maybe a,您可以缩写为Maybe a -> Maybe a您之前编写的签名.