为什么这个镜头功能需要类型签名?
Why does this lens function require a type signature?
我正在编写一个使用镜头库的函数,但奇怪的是,当我删除类型注释时代码无法编译。
{-# LANGUAGE TemplateHaskell, Rank2Types #-}
import Control.Lens
import Control.Monad.State
import Data.List (elemIndex)
data MyRecord = MyRecord { _someField :: [Int], _anotherField :: [String] }
makeLenses ''MyRecord
updateRecord :: Eq a => a -> Lens' b [a] -> (Int -> c) -> State b c
updateRecord elem lens f = do field <- view lens <$> get
case elemIndex elem field of
Just index -> return $ f index
Nothing -> do modify (over lens (++[elem]))
return . f $ length field
当我注释掉 updateRecord
的类型签名时,出现此错误:
• Couldn't match type ‘Const [a] s’ with ‘Identity s’
Expected type: ASetter s s [a] [a]
Actual type: Getting [a] s [a]
为什么在这种情况下需要类型签名?
问题是 lens
在两个上下文中使用,view lens
,其中需要类型:
Getting [a] s [a]
= ([a] -> Const [a] [a]) -> (s -> Const [a] s)
和 over lens ...
需要输入的地方:
ASetter s s [a] [a]
= ([a] -> Identity [a]) -> (a -> Identity s)
不幸的是,这些类型不统一。 (特别是,这些类型的最右边的部分,Const [a] s
和 Identity s
,不统一,这就是错误消息所说的。)当 GHC 试图推断 [=15= 的类型时] 在没有显式类型签名的类型检查 updateRecord
中,它根据 lens
在 view
中的使用推断出上面的第一种类型,但随后无法将其与出现的第二种类型统一起来over
.
然而,即使类型不统一,是一种更高级别的多态类型,可以分别专门用于每个类型,即:
Lens' s a
= Lens s s a a = forall f. Functor f => (a -> f s) -> (a -> f s)
只要 GHC 可以单独推断这种类型,比如通过显式类型签名,它就能够将这种更通用的类型与每个用途统一起来。
这只是其中之一,是更高级别类型的基本限制。你可以在一个小得多的例子中看到同样的现象。此函数 foo
不进行类型检查:
foo f = (f 10, f "hello")
但是添加类型签名就没问题了:
foo :: (forall a. a -> a) -> (Int, String)
foo f = (f 10, f "hello")
我正在编写一个使用镜头库的函数,但奇怪的是,当我删除类型注释时代码无法编译。
{-# LANGUAGE TemplateHaskell, Rank2Types #-}
import Control.Lens
import Control.Monad.State
import Data.List (elemIndex)
data MyRecord = MyRecord { _someField :: [Int], _anotherField :: [String] }
makeLenses ''MyRecord
updateRecord :: Eq a => a -> Lens' b [a] -> (Int -> c) -> State b c
updateRecord elem lens f = do field <- view lens <$> get
case elemIndex elem field of
Just index -> return $ f index
Nothing -> do modify (over lens (++[elem]))
return . f $ length field
当我注释掉 updateRecord
的类型签名时,出现此错误:
• Couldn't match type ‘Const [a] s’ with ‘Identity s’
Expected type: ASetter s s [a] [a]
Actual type: Getting [a] s [a]
为什么在这种情况下需要类型签名?
问题是 lens
在两个上下文中使用,view lens
,其中需要类型:
Getting [a] s [a]
= ([a] -> Const [a] [a]) -> (s -> Const [a] s)
和 over lens ...
需要输入的地方:
ASetter s s [a] [a]
= ([a] -> Identity [a]) -> (a -> Identity s)
不幸的是,这些类型不统一。 (特别是,这些类型的最右边的部分,Const [a] s
和 Identity s
,不统一,这就是错误消息所说的。)当 GHC 试图推断 [=15= 的类型时] 在没有显式类型签名的类型检查 updateRecord
中,它根据 lens
在 view
中的使用推断出上面的第一种类型,但随后无法将其与出现的第二种类型统一起来over
.
然而,即使类型不统一,是一种更高级别的多态类型,可以分别专门用于每个类型,即:
Lens' s a
= Lens s s a a = forall f. Functor f => (a -> f s) -> (a -> f s)
只要 GHC 可以单独推断这种类型,比如通过显式类型签名,它就能够将这种更通用的类型与每个用途统一起来。
这只是其中之一,是更高级别类型的基本限制。你可以在一个小得多的例子中看到同样的现象。此函数 foo
不进行类型检查:
foo f = (f 10, f "hello")
但是添加类型签名就没问题了:
foo :: (forall a. a -> a) -> (Int, String)
foo f = (f 10, f "hello")