定义签名中可能包含的haskell函数
我不清楚如何在haskell中编写函数签名,尤其是使用定义签名中可能包含的haskell函数,haskell,Haskell,我不清楚如何在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
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运行所有代码)似乎您对类型变量感到困惑。首先,在
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::maybeaa->maybeab
我们会得到这个家庭:
f :: Maybe Int -> Maybe Bool
f :: Maybe String -> Maybe String
f :: Maybe (Maybe Bool) -> Maybe Int
...
也就是说,a
和b
现在可以代表不同的类型,但是参数和结果仍然必须是可能是
你不能说的原因
f :: Maybe -> Maybe
是因为可能不是一个类型——它是一个类型构造函数。如果你给它一个类型,它会给你一个类型。因此,Maybe Int
和Maybe String
都是类型,一般来说,Maybe a
是类型,只要a
是类型
Maybe Int a
(解析为(Maybe Int)a
)没有意义,因为Maybe Int
不是类型构造函数——它不接受任何其他参数
建议阅读:来自LYAH。似乎您对类型变量感到困惑。首先,在
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::maybeaa->maybeab
我们会得到这个家庭:
f :: Maybe Int -> Maybe Bool
f :: Maybe String -> Maybe String
f :: Maybe (Maybe Bool) -> Maybe Int
...
也就是说,a
和b
现在可以代表不同的类型,但是参数和结果仍然必须是可能是
你不能说的原因
f :: Maybe -> Maybe
是因为可能不是一个类型——它是一个类型构造函数。如果你给它一个类型,它会给你一个类型。因此,Maybe Int
和Maybe String
都是类型,一般来说,Maybe a
是类型,只要a
是类型
Maybe Int a
(解析为(Maybe Int)a
)没有意义,因为Maybe Int
不是类型构造函数——它不接受任何其他参数
建议阅读:来自LYAH。可能是一个类型构造函数,本质上是一个类型级函数。它接受一个类型(例如Int
)并返回一个类型(例如可能是Int
)。类型的“类型”称为种类:具有值的类型,如Int
,称为*
。接受一个参数的类型构造函数的类型是*->*
。您可以使用:kind
/:k
命令在GHCi中看到这一点:
> :k Int
Int :: *
> :k Maybe
Maybe :: * -> *
> :k Either
Either :: * -> * -> *
在像maybea a->maybea a
这样的签名中,a
是一个类型变量,当您调用函数时,它会被替换为特定类型。(隐式地说,这意味着对于所有a.maybea->maybea
,如果启用扩展,例如ExplicitForall
或ScopedTypeVariables
,您可以自己编写)
因此,如果您在Maybe Int
上调用f::Maybe a->Maybe a
,那么f
在该调用站点具有类型Maybe Int->Maybe Int
,因为a
已被实例化为Int
编译器拒绝Maybe Int a
,因为您向Maybe
提供了两个参数,而它只接受一个参数。(a
不是参数的名称,而是类型的参数。)同样,它拒绝Maybe->Maybe
,因为您没有给Maybe
任何参数,所以您试图将两种类型的*->*
传递给函数arrow构造函数(>)
,它接受类型为*
的参数:
> :k (->)
(->) :: * -> * -> *
另一方面,可以编写类似于Maybe->Maybe
的内容,并将其扩展为maybea->maybea
,这有时可能很有用,但几乎可以肯定这不是您现在想要做的
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
type (~>) f g = forall a. f a -> g a
f :: Maybe ~> Maybe
f x = x
这里,类型同义词Maybe~>Maybe
扩展为forall a。可能是一个->可能是一个
,可以缩写为可能是一个->可能是一个
,您以前编写的签名。可能是一个类型构造函数,本质上是一个类型级函数。它接受一个类型(例如Int
)并返回一个类型(例如可能是Int
)。类型的“类型”称为种类:具有值的类型,如Int
,称为*
。接受一个参数的类型构造函数的类型是*->*
。您可以使用:kind
/:k
命令在GHCi中看到这一点:
> :k Int
Int :: *
> :k Maybe
Maybe :: * -> *
> :k Either
Either :: * -> * -> *
在像maybea a->maybea a
这样的签名中,a
是一个类型变量,当您调用函数时,它会被替换为特定类型。(隐式地说,这意味着对于所有a.maybea a->maybea a
,如果启用ex,您可以自己编写