gpt4 book ai didi

haskell - 从 Haskell 中的 where 子句函数访问参数

转载 作者:行者123 更新时间:2023-12-02 08:06:51 25 4
gpt4 key购买 nike

我知道对于“普通”函数,我可以从 where 子句中定义的函数中访问顶层参数。但是,当我对 monadic 函数尝试同样的事情时,我遇到了编译时错误。

这个有效:

module Main where

import Control.Monad.ST (ST, runST)
import Data.Array.ST (STUArray, newArray, readArray)

main :: IO ()
main = do
print $ runST $ do
arr <- newArray (0, 9) 0
checkArr arr
return ()

checkArr :: STUArray s Int Int -> ST s Bool
checkArr arr = do
val <- readArr arr
return $ val == 0
where
readArr :: STUArray s Int Int -> ST s Int
readArr arr = readArray arr 0

但这不是:

module Main where

import Control.Monad.ST (ST, runST)
import Data.Array.ST (STUArray, newArray, readArray)

main :: IO ()
main = do
print $ runST $ do
arr <- newArray (0, 9) 0
checkArr arr
return ()

checkArr :: STUArray s Int Int -> ST s Bool
checkArr arr = do
val <- readArr
return $ val == 0
where
readArr :: ST s Int
readArr = readArray arr 0

它会导致以下错误:

No instance for (Data.Array.Base.MArray (STUArray s) Int (ST s1)) arising from a use of ‘readArray’

为什么在readArr中访问不到checkArrarr参数?

最佳答案

首先请注意,错误消息说的是缺少实例声明而不是未知变量名称。此外,作为第一个提示,请注意错误消息包含两个不同的 ST标签: s来自STUArray (与函数的 arr 参数有关),另一个 s1ST s1 .那在哪里s1来自?确实,您的程序中没有提到它!

作为第二个提示,尝试删除 readArr 的签名声明,所以 where子句看起来就像

  where
readArr = readArray arr 0

突然间,类型检查和工作正常了。怎么回事?

答案是当你写了readArr :: ST s Int ,你的意思是 s来自 checkArr签名,但范围规则是这样的,这实际上引入了一个新的类型变量,类型检查器为您重命名为 s1 , 和 s不一定与 s1 匹配,因此类型错误。如果您省略此签名,则类型检查器能够自行派生出正确的类型。

如果你真的想把类型写在where中-像这样绑定(bind),有一个扩展! ScopedTypeVariables 允许您从函数中引用一个自由变量(s 签名中的 checkArr)。所以,添加一个 {-# LANGUAGE ScopedTypeVariables #-}并让类型检查器知道你希望通过写一个显式的 forall 来限定它的范围在顶级签名中:checkArr :: forall s. STUArray s Int Int -> ST s Bool .之后,您的代码将进行类型检查。

关于haskell - 从 Haskell 中的 where 子句函数访问参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50667905/

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