gpt4 book ai didi

arrays - 显示 IO 数组

转载 作者:行者123 更新时间:2023-12-04 05:38:54 24 4
gpt4 key购买 nike

当我一直在学习 haskell 时,我很喜欢纯粹的部分,但现在我在 monadic 和 IO 部分中磕磕绊绊,可能正在经历一些人觉得这门语言真正令人愤怒的地方。我解决了一个项目的欧拉问题,我想要一个可变数组,因为我必须经常按索引更新元素。我尝试了 Vectors,但无法让它们工作,所以我尝试了 Data.Array.IO。我可以很好地读取和写入元素,但我无法以我想要的方式在终端中显示数组。到目前为止,我有这个。

test = do
arr <- newArray (1,10) 37 :: IO (IOArray Int Int)
a <- readArray arr 1
writeArray arr 1 64
b <- readArray arr 1
dispArray arr
return ()

dispArray arr = do
(a,b) <- getBounds arr
printf "["
dispArray' arr a
printf "]\n"
where dispArray' arr i = do
(a,b) <- getBounds arr
if i < a || i > b
then return ()
else do
v <- readArray arr i
print v
dispArray' arr (i+1)

正如您所期望的那样,输出是这样的:
[64
37
37
37
37
37
37
37
37
37
]

但这很不方便,我想要这个 [64,37,37,37....像这样。我见过类似于 toList 的函数,但我不想要这个。我不想每次显示时都转换为列表。所以我想我需要使用 printf .所以我换了 print vprintf " %s," (show v) .但这不会编译。我不知道为什么。我以为会因为 print :: Show a => a -> IO ()show :: Show a => a -> String那么为什么它不起作用,因为 %s表示一个字符串?所以我然后把电话放在一起。看看 printf 是否可以工作。
printf " %s," "hello"
print v

编译并显示:
[ hello,64
hello,37
hello,37
hello,37
hello,37
hello,37
hello,37
hello,37
hello,37
hello,37
]

为什么我不能使用 show v ?为什么 Haskell IO 对初学者如此恼火?

最佳答案

这是一个有趣的类型检查难题。

调用 printf 的错误信息产生是

Could not deduce (PrintfType (m a0))
arising from the ambiguity check for `dispArray'

短语 Could not deduceambiguity通常暗示 GHC 具有
类型信息不足,无法得出应如何键入该程序的结论。这可能是一个真正的类型错误,但也有可能通过提供更多类型信息来修复它(这里就是这种情况)。

这里的罪魁祸首真的是 printf ,结合可变数组接口(interface)的灵 active ,并没有那么多Haskell的IO系统。 printf的类型是一个巧妙的 hack,但仍然是一个 hack。为了了解仅取决于格式字符串的各种类型的灵活数量的参数, printf有一种不是很安全也不是很丰富的类型:
printf :: PrintfType r => String -> r

所以我们真正确定的是第一个参数的类型是 String。 .其余的可以是任何类型 r属于类型类 PrintfType .

实例的细节无关紧要。有趣的是 show产生 String , 如果我们申请 printf转换为格式字符串,然后转换为 show - 产生第二个字符串,我们仍然留下一个相当无信息的类型:
> :t printf "%s," (show 2)
printf "%s," (show 2) :: PrintfType t => t

特别是,这里没有迹象表明结果将在 IO 中。单子(monad)。

如果 GHC 可以从上下文中得出您在 IO 中的结论,这通常不会成为问题。 .但在 dispArray' 内,您调用的唯一其他函数是 readArray , getBounds , return (和 dispArray' 递归)。这些函数都没有指定它位于 IO 中。任何一个。特别是,所有数组函数都在 monad 上重载,例如:
getBounds :: (Ix i, MArray a e m) => a i e -> m (i, i)

(事实上​​, getBounds 也可以在 ST monad 上下文中工作。)所以在 dispArray' 中根本没有任何内容。这决定了你住在 IO .这反过来意味着 GHC 无法解析 printf 的类型。 .

正如我所说,这是 printf 所需的灵 active 的结果。那 printf它本身不能提供这些信息,它必须在外部可用。

解决方案很简单。正如其中一条评论所建议的,将调用的结果类型注释到 printf 就足够了。 :
printf "%s," (show v) :: IO ()

当您使用 printf无论如何(如果您实际上只对十进制数数组感兴趣),您也可以使用:
printf "%d," v :: IO ()

dispArray' 的定义中的任何其他内容提供类型签名也足够了(但读者不太清楚)。以便将返回类型固定为 IO () .例如,您可以注释 return ()then - if 的分支表达:
return () :: IO ()

关于arrays - 显示 IO 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15776937/

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