gpt4 book ai didi

haskell - 为什么 haskell 编译器可以推断出这种类型,而 ghci 不能?

转载 作者:行者123 更新时间:2023-12-03 14:58:53 26 4
gpt4 key购买 nike

我正在处理 following book学习 Haskell - 特别关注 randomness 的章节:

我正在运行以下文件作为文件 three-coins.hs :

import System.Random 

threeCoins :: StdGen -> (Bool, Bool, Bool)
threeCoins gen =
let (firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
(thirdCoin, newGen'') = random newGen'
in (firstCoin, secondCoin, thirdCoin)

main = print ( threeCoins (mkStdGen 21) )

然后我用 runhaskell three-coins.hs 执行并获得类似于以下内容的输出:
(True,True,True)

现在他们在笔记中指出了这一点:

Notice that we didn't have to do random gen :: (Bool, StdGen). That's because we already specified that we want booleans in the type declaration of the function. That's why Haskell can infer that we want a boolean value in this case.



太棒了。

现在,当我在 ghci 中运行它时使用以下代码:
import System.Random 

:{
threeCoins :: StdGen -> (Bool, Bool, Bool)
threeCoins gen =
let (firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
(thirdCoin, newGen'') = random newGen'
in (firstCoin, secondCoin, thirdCoin)
:}

我得到以下回复:
<interactive>:6:9: error:
• Ambiguous type variable ‘t0’
prevents the constraint ‘(Random t0)’ from being solved.
• When checking that the inferred type
newGen :: forall t. Random t => StdGen
is as general as its inferred signature
newGen :: StdGen
In the expression:
let
(firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
(thirdCoin, newGen'') = random newGen'
in (firstCoin, secondCoin, thirdCoin)
In an equation for ‘threeCoins’:
threeCoins gen
= let
(firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
....
in (firstCoin, secondCoin, thirdCoin)

这很有趣。有点像他们在书中警告我们的错误。

因此,如果我们修改代码以将类型提示放入:
import System.Random 

:{
threeCoins :: StdGen -> (Bool, Bool, Bool)
threeCoins gen =
let (firstCoin, newGen) = random gen :: (Bool, StdGen)
(secondCoin, newGen') = random newGen :: (Bool, StdGen)
(thirdCoin, newGen'') = random newGen' :: (Bool, StdGen)
in (firstCoin, secondCoin, thirdCoin)
:}

效果很好 - 我们可以使用以下方法对其进行测试:
threeCoins (mkStdGen 21) 

并得到这个结果
(True,True,True)

嗯 - 这工作。所以 Haskell 编译器可以从我们提供的类型推断出我们想要一个 bool 值,但 ghci 不能。

我的问题是: 为什么 haskell 编译器可以推断出这种类型,而 ghci 不能?

最佳答案

正如 chi 已经评论的那样,此代码仅在 monomorphism restriction 时有效。已启用。该限制使编译器为任何非函数定义选择一种特定类型,即其中没有类型变量的签名,如 alength :: [a] -> Int .因此(除非您手动指定了本地签名)编译器在选择之前到处寻找这种类型可能是什么的提示。在您的示例中,它看到 firstCoin secondCoin thirdCoin用于最终结果,在顶层签名声明为 (Bool, Bool, Bool) ,因此它推断所有硬币必须具有类型Bool .

在这样一个简单的例子中这很好,但在现代 Haskell 中,您经常需要更通用的值,因此您可以在多个不同类型的上下文中使用它们或作为 Rank-2 函数的参数。你总是可以通过给出明确的签名来实现这一点,但特别是在 GHCi 中这很尴尬(它通常被称为“可怕的单态限制”),因此几个版本之前决定在 GHCi 中默认禁用它。

从概念上讲,firstCoin secondCoin thirdCoin等也可能比 Bool 更通用: random毕竟能够产生任何合适类型的随机值(即任何具有 Random 实例的类型)。所以原则上,本地定义可以有一个多态类型,像这样:

threeCoins :: StdGen -> (Bool, Bool, Bool)  
threeCoins gen =
let firstCoin, secondCoin, thirdCoin :: Random r => r
(firstCoin, newGen) = random gen
(secondCoin, newGen') = random newGen
(thirdCoin, newGen'') = random newGen'
in (firstCoin, secondCoin, thirdCoin)

这基本上是关闭单态限制时发生的情况,正如您通过使用以下行编译原始示例所看到的那样
{-# LANGUAGE NoMonomorphismRestriction #-}

在上面。

麻烦的是,您的代码实际上不适用于那些通用的本地签名。原因有点牵扯,基本上是 r的类型信息变量必须先传播回元组,然后才能在 random 中使用。生成器,由于我现在也不明白的原因,Hindley-Milner 类型系统无法做到这一点。

最好的解决方案是不要手动展开元组,这很尴尬,而是使用 random monad , 像这样:
import System.Random 
import Data.Random

threeCoins :: RVar (Bool, Bool, Bool)
threeCoins = do
firstCoin <- uniform False True
secondCoin <- uniform False True
thirdCoin <- uniform False True
return (firstCoin, secondCoin, thirdCoin)

main = print . sampleState threeCoins $ mkStdGen 21

无论有无单态限制都可以使用,因为 firstCoin secondCoin thirdCoin现在来自一元绑定(bind), which is always monomorphic .

顺便说一句,因为你在一个单子(monad)中,所以你可以使用标准组合子,从而很容易地把它缩短为
import Control.Monad (replicateM)

threeCoins :: RVar (Bool, Bool, Bool)
threeCoins = do
[firstCoin,secondCoin,thirdCoin] <- replicateM 3 $ uniform False True
return (firstCoin, secondCoin, thirdCoin)

关于haskell - 为什么 haskell 编译器可以推断出这种类型,而 ghci 不能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48006676/

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