我不清楚如何在haskell中编写函数签名,尤其是使用Maybe
。考虑:
f :: Maybe a -> Maybe a
f = \a -> a
main = print (f (Just 5))
这可行,但为什么功能签名不能这样呢?
f :: Maybe -> Maybe
因为f
只采用Maybe
类型并返回Maybe
类型。
相关:如果我想让Maybe类型更具体并且是Maybe Int
,为什么这不起作用?
f :: Maybe Int a -> Maybe Int a
f = \a -> a
main = print (f (Just (Int 5)))
(我正在使用runhaskell test.hs
运行所有代码)
答案 0 :(得分:10)
好像你对类型变量感到困惑。首先,在
f :: Maybe a -> Maybe a
f = \a -> a
第一行中的a
与第二行中的a
无关,我们可以这样写:
f :: Maybe a -> Maybe a
f = \x -> x
甚至
f :: Maybe foo -> Maybe foo
f = \bar -> bar
a
是代表类型的变量。因此f
声明f
同时包含大量类型:
f :: Maybe Int -> Maybe Int
f :: Maybe String -> Maybe String
f :: Maybe (Maybe Bool) -> Maybe (Maybe Bool)
...
等等。正如我怀疑你所想的那样,这不是一些“标记”的论点。两个a
相同的事实意味着参数类型必须是相同的结果类型。如果我们说f :: Maybe a -> Maybe b
我们会得到这个家庭:
f :: Maybe Int -> Maybe Bool
f :: Maybe String -> Maybe String
f :: Maybe (Maybe Bool) -> Maybe Int
...
也就是说,a
和b
现在可以代表不同的类型,但参数和结果仍然必须是Maybe
。
你不能说的原因
f :: Maybe -> Maybe
是因为Maybe
不是类型 - 它是类型构造函数。如果你给它一个类型,它会给你一个类型。因此,Maybe Int
和Maybe String
是类型,只要Maybe a
是类型,a
就是一种类型。
Maybe Int a
(解析为(Maybe Int) a
)没有意义,因为Maybe Int
不是类型构造函数 - 它不再接受任何参数。
建议阅读:来自LYAH的Types and Typeclasses。
答案 1 :(得分:5)
endpointConfiguration.DisableFeature<TimeoutManager>();
是一个类型构造函数,本质上是一个类型级函数。它需要一个类型(例如Maybe
)并返回一个类型(例如Int
)。类型的“类型”称为 types :具有值的类型(如Maybe Int
)称为Int
。采用一个参数的类型构造函数的类型是*
。您可以使用* -> *
/ :kind
命令在GHCi中看到此内容:
:k
在> :k Int
Int :: *
> :k Maybe
Maybe :: * -> *
> :k Either
Either :: * -> * -> *
之类的签名中,Maybe a -> Maybe a
是一个类型变量,在您调用该函数时会被特定类型替换。 (隐含地,这意味着a
,如果您启用forall a. Maybe a -> Maybe a
或ExplicitForall
等扩展程序,则可以自行编写。{/ p>
因此,如果您在ScopedTypeVariables
上致电f :: Maybe a -> Maybe a
,那么Maybe Int
在该呼叫网站上的类型为f
,因为Maybe Int -> Maybe Int
已经实例化到a
。
编译器拒绝Int
,因为当它只接受一个参数时,你会向Maybe Int a
提供两个参数。 (Maybe
不是参数的名称,而是类型的参数。)同样,它拒绝a
,因为您没有给Maybe -> Maybe
参数,所以你正在尝试将两种类型的Maybe
传递给函数箭头构造函数* -> *
,它接受类型为(->)
的参数:
*
顺便说一句,可以写一些类似> :k (->)
(->) :: * -> * -> *
的内容并将其扩展为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
扩展为Maybe ~> Maybe
,可以缩写为forall a. Maybe a -> Maybe a
,即您之前编写的签名。