在Haskell中,如何在foldLeft中使用putStrLn

wbrvyc0a  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(99)

TL; DR。

foldLeft (\_ x -> putStrLn x) (pure ()) ("2":."1":.Nil)

为什么上面的代码输出
而不是

2
1

完整问题

我在做FP课程的练习
https://github.com/system-f/fp-course/blob/5e0848b4eacb3ddff65553ab5beb6447b73f61b3/src/Course/FileIO.hs#L97
对此我有两个解决方案。

printFiles ps = void . sequence $ (uncurry printFile) <$> ps
printFiles = foldLeft (\_ (fp, content) -> printFile fp content) (pure ())

第一个是正确的,可以打印为问题的要求。

>> :main "share/files.txt"
============ share/a.txt
the contents of a

============ share/b.txt
the contents of b

============ share/c.txt
the contents of c

第二次打印如下。

>> :main "share/files.txt"
============ 
share/c.txt
the contents of c

看起来pure ()只收集foldLeft的最后一个printFile fp content
如何使pure ()又名IO ()收集所有putStrLnfoldLeft

olmpazwi

olmpazwi1#

您构造一个putStrLn "1"作为最终结果,并由此生成。注意IO a * 不是 * 一个 * 发生过 * 的动作,或者总是会发生,你应该把它看作是动作的某种委托,所以是一个配方,你可以把合并配方和**(>>) :: Monad m => m a -> m b -> m b**结合起来,创建一个 * 新的 * 配方,它首先运行第一个操作数,然后是正确的操作数。
所以在这种情况下,我们可以用以下方法修复它:

foldLeft (\prev x -> prev >> putStrLn x) (pure ()) ("2":."1":.Nil)

所以最终结果将是putStrLn "2" >> putStrLn "1",它是IO (),当调用时将首先打印"2",然后打印"1"

yptwkmov

yptwkmov2#

因为Haskell是引用透明的,所以你总是可以通过手动计算表达式来回答这样的问题,即内联函数调用和beta缩减,直到很明显发生了什么:

foldLeft (\_ x -> putStrLn x) (pure ()) ("2":."1":.Nil)
  = {- (recursive) definition of `foldLeft` for Cons case -}
    foldLeft (\_ x -> putStrLn x)
       ((\_ x -> putStrLn x) (pure ()) "2")
       ("1":.Nil)
  = {- beta reduction -}
    foldLeft (\_ x -> putStrLn x)
       (putStrLn "2")
       ("1":.Nil)
  = {- definition of `foldLeft` for Cons case -}
    foldLeft (\_ x -> putStrLn x)
       ((\_ x -> putStrLn x) (putStrLn "2") "1")
       Nil
  = {- beta reduction -}
    foldLeft (\_ x -> putStrLn x)
       (putStrLn "1")  -- woops, the "2" has vanished in the `_` argument
       Nil
  = {- definition of `foldLeft` for Nil case -}
    putStrLn "1"

所以这就是你得到的:一张"1"的照片奥托赫,根据威廉货车昂塞姆的建议,

foldLeft (\prev x -> prev >> putStrLn x) (pure ()) ("2":."1":.Nil)
  = {- definition of `foldLeft` for Cons case -}
    foldLeft (\prev x -> prev >> putStrLn x)
       ((\prev x -> prev >> putStrLn x) (pure ()) "2")
       ("1":.Nil)
  = {- beta reduction -}
    foldLeft (\prev x -> prev >> putStrLn x)
       (pure () >> putStrLn "2")
       ("1":.Nil)
  = {- definition of `foldLeft` for Cons case -}
    foldLeft (\prev x -> prev >> putStrLn x)
       ((\prev x -> prev >> putStrLn x) (pure () >> putStrLn "2") "1")
       Nil
  = {- beta reduction -}
    foldLeft (\prev x -> prev >> putStrLn x)
       ((pure () >> putStrLn "2") >> putStrLn "1")
       Nil
  = {- definition of `foldLeft` for Nil case -}
    pure () >> putStrLn "2" >> putStrLn "1"

相关问题