Joe*_*son 7 haskell haskell-lens
I'm writing a function which uses the lenses library, but curiously, the code doesn't compile when I remove the type annotation.
{-# 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
Run Code Online (Sandbox Code Playgroud)
When I comment out the type signature for updateRecord, I get this error:
• Couldn't match type ‘Const [a] s’ with ‘Identity s’
Expected type: ASetter s s [a] [a]
Actual type: Getting [a] s [a]
Run Code Online (Sandbox Code Playgroud)
Why is the type signature required in this case?
问题是lens在两个上下文中使用view lens,它们需要具有类型:
Getting [a] s [a]
= ([a] -> Const [a] [a]) -> (s -> Const [a] s)
Run Code Online (Sandbox Code Playgroud)
以及over lens ...要求输入的类型:
ASetter s s [a] [a]
= ([a] -> Identity [a]) -> (a -> Identity s)
Run Code Online (Sandbox Code Playgroud)
不幸的是,这些类型不能统一。(特别是这些类型的最右边部分,Const [a] s以及Identity s,请不要统一,这就是错误消息的意思。)当GHC尝试lens在updateRecord没有显式类型签名的情况下推断类型检查中的类型时,它将推断出上面的第一个类型对于lens基于其使用view,但随后无法与中出现的第二类型结合本over。
但是,即使类型不统一,也可以有一个更高级别的多态类型可以分别专用于每个类型,即:
Lens' s a
= Lens s s a a = forall f. Functor f => (a -> f s) -> (a -> f s)
Run Code Online (Sandbox Code Playgroud)
只要GHC可以通过显式类型签名分别推断出此类型,就可以将每种用途统一此更通用的类型。
这只是其中之一,是较高等级类型的基本限制。您可以通过一个较小的示例看到相同的现象。此函数foo不进行类型检查:
foo f = (f 10, f "hello")
Run Code Online (Sandbox Code Playgroud)
但是添加类型签名就可以了:
foo :: (forall a. a -> a) -> (Int, String)
foo f = (f 10, f "hello")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
99 次 |
| 最近记录: |