在什么条件下我们应该在类型声明中使用`[] a`?

use*_*628 3 haskell type-declaration

我只看到一个表达

fmap_List :: (a -> b) -> [] a -> [] b
-- "[] a" means "[a]", for types.
fmap_List f [] = []
fmap_List f (x:xs) = f x : fmap_List f xs
Run Code Online (Sandbox Code Playgroud)

既然[] a意味着[a],为什么我们不[a]直接放?我们应该使用一些特殊情况[] a吗?

Jon*_*rdy 11

它只是避免语法糖[a]作为一种说明f类型参数fmap :: Functor f => (a -> b) -> f a -> f b被类型构造函数替换的方式[],就像任何其他类型的构造函数一样.

也就是说,您可以将类型编写[a][] a当您想要强调与某些类型构造函数的多态性签名的关系时,如fmap:

fmap       :: Functor f => (a -> b) ->     f a ->     f b

-- f = []
fmap_List  ::              (a -> b) ->    [] a ->    [] b
fmap_List = fmap

-- f = Maybe
fmap_Maybe ::              (a -> b) -> Maybe a -> Maybe b
fmap_Maybe = fmap
Run Code Online (Sandbox Code Playgroud)

或者join:

join      :: Monad m =>  m ( m a) ->  m a
join_List ::            [] ([] a) -> [] a
Run Code Online (Sandbox Code Playgroud)

这完全相同[[a]] -> [a],只是让它更清楚m= [].

[] a[]应用于类型变量的类型构造函数a.[] a[a]有那种*,该种由值居住类型,例如Int,Char,Maybe Int,或Either String Int.[]有种类* -> *,那种称取一个类型参数,并产生一个类型,结果类型,例如[],Maybe,Identity,或Either e.

您可以定义见本,例如instance Monad [],我们愿意给予构造 [](种* -> *)作为参数传递给Monad(种(* -> *) -> Constraint),而不是一个类型(一种*制造)与构造等instance Monad ([] a).这就像使用Maybe代替Maybe a,Maybe Int,Maybe String,&C.

使用TypeApplicationspragma,您可以显式地将多态函数应用于类型参数,例如在GHCi中:

> :set -XTypeApplications

> :type fmap @[]
fmap @[] :: (a -> b) -> [a] -> [b]

> :type fmap @Maybe
fmap @Maybe :: (a -> b) -> Maybe a -> Maybe b

> :type fmap @[] @Int @Char
fmap @[] @Int @Char :: (Int -> Char) -> [Int] -> [Char]

> :type fmap @[] @_ @Bool
fmap @[] @_ @Bool :: (a -> Bool) -> [a] -> [Bool]
Run Code Online (Sandbox Code Playgroud)

这对于弄清楚如何使用多态函数,或通过将类型专门化为(更多)具体实例来记录您正在使用这样的函数的容器或monad非常有用:

> :type traverse
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)

> :type traverse @[] @IO
traverse @[] @IO :: (a -> IO b) -> [a] -> IO [b]
Run Code Online (Sandbox Code Playgroud)

你也可以向GHCi询问一种类型,以便更好地理解种类:

> :kind Either
Either :: * -> * -> *

> :kind Either String
Either String :: * -> *

> :kind Either String Int
Either String Int :: *

> :kind []
[] :: * -> *

> :kind [] Int
[] Int :: *

> :kind [Int]
[Int] :: *

> :kind Functor
Functor :: (* -> *) -> Constraint

> :kind Num
Num :: * -> Constraint
Run Code Online (Sandbox Code Playgroud)