gpt4 book ai didi

Haskell初学者,尝试输出一个列表

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

我想这里的每个人都已经看到过这些(或至少类似)问题之一,但我仍然需要问,因为我在任何地方都找不到这个问题的答案(主要是因为我不知道我到底是什么)应该寻找)

我写了这个小脚本,其中 printTriangle 应该打印出帕斯卡三角形。

fac = product . enumFromTo 2

binomial n k = (product (drop (k-1) [2..n])) `div` (fac (n-k))

pascalTriangle maxRow =
do row<-[0..maxRow-1]
return (binomialRow row)
where
binomialRow row =
do k<-[0..row]
return (binomial row k)

printTriangle :: Int -> IO ()
printTriangle rows = do row<-(triangle)
putStrLn (show row)
where
triangle = pascalTriangle rows

现在,出于对训练有素的人来说可能显而易见的原因,但对我来说完全笼罩在神秘之中,当我尝试在 ghci 中加载它时,出现以下错误:

   Couldn't match expected type `IO t0' with actual type `[[Int]]'
In a stmt of a 'do' expression: row <- (triangle)
In the expression:
do { row <- (triangle);
putStrLn (show row) }
In
an equation for `printTriangle':
printTriangle rows
= do { row <- (triangle);
putStrLn (show row) }
where
triangle = pascalTriangle rows

我想做的是像这样调用 printTriangle :

printTriangle 3

我得到这个输出:

[1]
[1,1]
[1,2,1]

如果有人可以向我解释为什么我在这里所做的事情不起作用(说实话,我不太确定我在这里到底做了什么;我习惯了命令式语言,而整个函数式编程的事情就是对我来说仍然很困惑),以及如何以一种不那么愚蠢的方式做到这一点,那就太好了。

提前致谢。

最佳答案

您在评论中说您认为列表是 monad,但现在您不确定 - 好吧,您是对的,列表 monad!那么为什么你的代码不起作用呢?

嗯,因为IO也是一个单子(monad)。所以当编译器看到printTriangle :: Int -> IO ()时,然后是 do 符号,它表示“啊哈!我知道该怎么做!他正在使用 IO monad!”尝试想象一下,当它发现里面不是 IO monad,而是列表 monad 时,它会感到多么震惊和沮丧!

所以这就是问题所在:要打印,并与外界打交道,你需要使用 IO monad;在函数内部,您尝试使用列表作为 monad。

让我们看看这是一个什么问题。 do-notation 是 Haskell 的语法糖,用来引诱我们进入它的蛋糕屋并吃掉我们......我的意思是它是 >>= 的语法糖。 (发音为“bind”)来引诱我们使用 monad(并享受它)。所以我们写 printTriangle使用绑定(bind):

printTriangle rows = (pascalTriangle rows) >>= (\row -> 
putStrLn $ show row)

好吧,这很简单。现在我们看到什么问题了吗?好吧,让我们看看类型。绑定(bind)的类型是什么?胡格尔 说:(>>=) :: Monad m => m a -> (a -> m b) -> m b 。好的,谢谢胡格尔。所以基本上,bind 想要一个 monad 类型包装一个类型 a 个性,一个将 a 类型个性转换为(相同)monad 类型包装一个 type-b 个性的函数,并最终得到(相同)monad 类型包装一个类型 - b 个性。

所以在我们的printTriangle中,我们有什么?

  • pascalTriangle rows :: [[Int]] -- 所以我们的单子(monad)是 [] ,个性为[Int]
  • (\row -> putStrLn $ show row) :: [Int] -> IO () -- 这里的 monad 是 IO,个性是 ()

好吧,废话。 Hoogle 非常清楚地告诉我们,我们必须匹配我们的 monad 类型,相反,我们给出了 >>=一个列表 monad,以及一个生成 IO monad 的函数。这使得 haskell 表现得像个 child 子:它闭上眼睛,跺在地板上尖叫着“不!不!不!”甚至不会查看你的程序,更不用说编译它了。

<小时/>

那么我们如何安抚 Haskell 呢?嗯,其他人已经提到了mapM_ 。向顶级函数添加显式类型签名也是一个好主意——它有时可以帮助您更快而不是更晚地获得编译错误(并且您会得到它们;毕竟这是 Haskell :) ),这使得更容易理解错误消息。

我建议编写一个函数来将你的 [[Int]]成一个字符串,然后将字符串单独打印出来。通过将字符串转换与 IO 麻烦分开,这将使您能够继续学习 Haskell,而不必担心 mapM_和 friend 们,直到你做好准备。

showTriangle :: [[Int]] -> String
showTriangle triangle = concatMap (\line -> show line ++ "\n") triangle

showTriangle = concatMap (\line -> show line ++ "\n")

然后printTriangle容易得多:

printTriangle :: Int -> IO ()
printTriangle rows = putStrLn (showTriangle $ pascalTriangle rows)

printTriangle = putStrLn . showTriangle . pascalTriangle

关于Haskell初学者,尝试输出一个列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8100514/

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