gpt4 book ai didi

haskell - 为什么这个镜头功能需要类型签名?

转载 作者:行者123 更新时间:2023-12-04 11:33:14 26 4
gpt4 key购买 nike

我正在编写一个使用镜头库的函数,但奇怪的是,当我删除类型注释时代码不会编译。

{-# 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] sIdentity 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)

只要GHC能单独推断出这种类型,比如说通过显式类型签名,它能够将这种更通用的类型与每种用途统一起来。

这只是其中之一,是更高等级类型的基本限制。你可以通过一个小得多的例子看到同样的现象。这个功能 foo不进行类型检查:
foo f = (f 10, f "hello")

但是添加一个类型签名就可以了:
foo :: (forall a. a -> a) -> (Int, String)
foo f = (f 10, f "hello")

关于haskell - 为什么这个镜头功能需要类型签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57066103/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com