gpt4 book ai didi

haskell - 类型推断的微妙之处

转载 作者:行者123 更新时间:2023-12-02 10:41:01 25 4
gpt4 key购买 nike

我很难理解为什么推断的类型签名与我期望的不同。让我们举一个例子(我试图让它尽可能短):

import Control.Applicative
import Data.Word
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Token
import Text.Parsec.Language (emptyDef)
import Text.Parsec.Prim
import Data.Functor.Identity

--parseUInt' :: Num b => ParsecT String u Identity b
parseUInt' = fromInteger <$> decimal (makeTokenParser emptyDef)
--parseUInt1 = fromInteger <$> decimal (makeTokenParser emptyDef)
--parseUInt2 = fromInteger <$> decimal (makeTokenParser emptyDef)

parsePairOfInts = do
x <- parseUInt'
char ','
y <- parseUInt'
return $ (x, y)

parseLine :: String -> Either ParseError (Word32, Word8)
parseLine = parse parsePairOfInts "(error)"

main = print . show $ parseLine "1,2"

此代码无法编译:

test.hs:21:19:
Couldn't match type ‘Word32’ with ‘Word8’
Expected type: Parsec String () (Word32, Word8)
Actual type: ParsecT String () Identity (Word32, Word32)
In the first argument of ‘parse’, namely ‘parsePairOfInts’
In the expression: parse parsePairOfInts "(error)"
Failed, modules loaded: none.

但是如果我取消注释 parseUInt' 的类型签名,它就可以正常编译。

同时,如果我在GHCi中查询类型信息,则如下所示:

λ>:t (fromInteger <$> decimal (makeTokenParser emptyDef))
(fromInteger <$> decimal (makeTokenParser emptyDef))
:: Num b => ParsecT String u Identity b

但是,如果我没有显式指定类型签名,“b”类型就会以某种方式固定为 Word32

如果我用两个不同(但实现相同)的函数 parseUInt1parseUInt2 替换 parseUInt',代码也会编译。

我认为,如果我不指定函数的类型,则推断的类型必须是限制最少的(Num b =>...),但不知怎的,情况并非如此。

我在这里真正缺少什么?

最佳答案

我认为这就是可怕的MonomorphismRestriction 的作用。如果您不提供类型签名,则当函数在代码中的其他位置实例化为具体类型时,ghc 会尝试推断具体类型签名。 ghc 发现您使用该函数将 Word32 解析为 parsePairOfInt 的第一行,然后修复 parseUInt' 在到达第二次使用 parseUInt' 两行之前转换为该类型。这会导致类型错误,因为类型已实例化为 Word32,现在类型需要为 Word8

关于haskell - 类型推断的微妙之处,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25902370/

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