English 中文(简体)
Lazy evaluation and IO的副作用混淆
原标题:Lazy evaluation and IO side effect confusion

该守则(摘自 YouLearn A Haskell ):

main = do   putStr "Hey, "  
            putStr "I m "  
            putStrLn "Andy!"  

似乎指向 des子

main =        putStr "Hey, " >>=  
       (\_ -> putStr "I m "  >>= 
       (\_ -> putStrLn "Andy!"))

根据我的理解,可以将其解释为“为了将StrLn“Andy”改为“ 我首先需要放下“一米”,并为了做到这一点,我首先需要删除“头盔”;

I disagree with this interpretation, which is annoying because the compiler obviously doesn t and leaves me feeling confused. The problem I have with it is that the lambdas ignore their arguments, during lazy evaluation isn t this sort of thing supposed to be recognised and short-circuited?

Also, sure, the binding returns an IO action, and when that IO action falls into main it gets executed. But what s to stop it from printing "Hey, Andy!I m "? I suspect it s whatever bind is doing.

并且,“IO(I)”类的IO行动如何掌握足够的信息,使运行时间系统能够印刷“Hey, I m/ 国际交易日志(IO)与“Hello World”或“Hello World”的印刷版本有何不同?

考虑另一页,从阴道一页,mon:

制糖:

do
  putStrLn "What is your name?"
  name <- getLine
  putStrLn ("Nice to meet you, " ++ name ++ "!")

Desugared版本:

putStrLn "What is your name?" >>= 
   (\_ ->
      getLine >>=
         (
ame ->
            putStrLn ("Nice to meet you, " ++ name ++ "!")))

这里的情况类似。

我认为,我只需要看到对国际独立组织具有约束力的定义,然后是清楚的。 如果有人能帮助我,如何实际评估该方案并确定产生副作用的确切时间,那将大有帮助。

最佳回答

Read the "Tackling the awkward squad" paper by Simon Peyton Jones.

For related questions, see

Take any such explanation including mine with a grain of salt - no hand-waving can replace a rigorous peer-reviewed paper, and the explanations are necessarily over-simplifications.

一种非常粗略的观点是:>>=。 清单构造者:

data IO = [Primitive] 

IO子系统对<代码>main的价值进行分解,并消耗该清单。 页: 1 因此,你可能想研究一下上面的Haskell切入点的定义(<>main,bind,这并不令人感兴趣。

You can also read papers on history of haskell and look at earlier versions of IO subsystem for insight of what is going on.

并参看。 C 语句完全由Conal Elliott担任。

功能纯度的定义是非自然的,我记得一份阐述定义的文件,但我不记得标题。

问题回答

Looking at IO in a real Haskell implementation will probably confuse more than it enlightens. But think of IO as being defined like this (this assumes you know GADTs):

data IO a where
    Return a :: IO a
    Bind :: IO a -> (a -> IO b) -> IO b
    PutStr :: String -> IO ()
    GetLine :: IO String

instance Monad IO where
    return = Return
    (>>=) = Bind

putStr :: String -> IO ()
putStr = PutStr

getLine :: IO String
getLine = GetLine

因此,当你评价一个方案(类别IO ()时,所有方案都是为了建立IO()类型的数据结构,说明一旦执行,将如何与世界互动。 那么,你可以想象,正在C等地写出执行引擎,而且会发生任何效果。

So

main = do   putStr "Hey, "  
            putStr "I m "  
            putStrLn "Andy!"  

这与

main = Bind (PutStr "Hey, ") ( _ -> Bind (PutStr "I m ") ( _ -> PutStr "Andy!"))

但这些顺序来自执行发动机的运行方式。

说了,我不了解实际执行《公约》的情况。 实际执行通常作为代表实际世界的象征性国家mon(这是保证分级的),如“troc” ,如“pt” ,即“pt-p. / . ” 等,只要求C级职能。

I think I just need to see the definition of bind for IO and then it will be all clear.

是的,你应当这样做。 这实际上非常容易,如果我正确的话,它就好像。

newtype IO = IO (RealWorld -> (a, RealWorld))

(IO f) >>= g = ioBind f g
    where
       ioBind :: (RealWorld -> (a, RealWorld)) -> (a -> IO b) -> RealWorld -> (b, RealWorld)
       ioBind f g rw = case f rw of
            (a, rw@RealWorld) -> case g a of
                IO b -> b rw

“骗局”是指每个国际交易日志的价值实际上基本上都是一种功能,但为了评估这种价值,你需要一种类型的标记:。 只有一个例子可以提供这种价值——运行时间制度(当然,职能不可指名)。

我认为,如果你把行动再次视为职能,那将更加容易理解。 你具有约束力的榜样(do{ foo <-accessLine ;pageStrLn foo ;})与以下职能相近:

apply arg func = func (arg)

除该职能为交易外。 因此,如果只有<代码>(arg)成功填写,则对我们的电话<代码>func(arg)进行评价。 否则,我们的行动中就有

这与普通职能不同,因为当时Haskell在继续实施该方案之前,如果是<代码>(arg),则真正确实确实确实确实会提供t care。

我认为,我只需要看到<代码>bind>对IO的定义,然后是明确的。

 -- ghc-8.6.5/libraries/base/GHC/Base.hs; line 1381
bindIO :: IO a -> (a -> IO b) -> IO b
bindIO (IO m) k = IO ( s -> case m s of (# new_s, a #) -> unIO (k a) new_s)

 -- ghc-8.6.5/libraries/base/GHC/Base.hs; line 1387
unIO :: IO a -> (State# RealWorld -> (# State# RealWorld, a #))
unIO (IO a) = a

www.un.org/Depts/DGACM/index_french.htm 在单独的模块中申报类型:

 -- ghc-8.6.5/libraries/ghc-prim/GHC/Types.hs; line 169
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))

(IObind的操作者,可在查询。) How to Declare an Imperative by Philip Wadler.


如果有人能帮助我,如何实际评估该方案并确定产生副作用的确切时间,那将大有帮助。

Let s rewrite bindIO:

  • http://downloads.haskell.org/%7Eghc/7.8.4/docs/html/users_guide/bang-patterns.html 取代<条码><>。

  • to extract the action from its first parameter using unIO:

    bindIO :: IO a -> (a -> IO b) -> IO b
    bindIO m k = IO ( s -> let !(# new_s, a #) = unIO m s in unIO (k a) new_s)
    

现在请您扩大这一版本: 学习你 A Haskell,例如:

main =        putStr "Hey, " >>=  
       (\_ -> putStr "I m "  >>= 
       (\_ -> putStrLn "Andy!"))
  1. 改为:

    main = bindIO (putStr "Hey, ")
                  (\_ -> bindIO (putStr "I m ")
                                (\_ -> putStrLn "Andy!"))
    
  2. Now for the finicky part - expanding all the calls to bindIO; all going well, the program would eventually resemble:

    main = IO (s0 -> let !(# s1, _ #) = unIO (putStr "Hey, ") s0 in
                      let !(# s2, _ #) = unIO (putStr "I m ") s1 in
                      unIO (putStrLn "Andy!") s2)
    
  3. One other change - it s optional, but it helps to clarify what s going on here:

    main = IO (s0 -> let !(# s1, _ #)  = unIO (putStr "Hey, ") s0 in
                      let !(# s2, _ #)  = unIO (putStr "I m ") s1 in
                      let !(# s3, a3 #) = unIO (putStrLn "Andy!") s2) in
                      (# s3, a3 #))
    
    • 根据我的理解,这可被解释为: 以便putStrLn “Andy<>/code>。 首先需要<代码>putStr“I m,并为了做到这一点,我首先需要putStr “Hey,

    Correct: because of how s0, s1, s2 and s3 are being used (once) in the program, which establishes an order of evaluation. That ordering allows putStr and putStrLn to use effects directly to print out their respective arguments.

So, unlike e.g. Standard ML (which uses syntactic ordering), Haskell relies on data dependencies to ensure I/O happens in the required order - the do-notation is merely a convenience.


我面临的问题是,拉姆布达斯无视其论点,在zy评价期间,这难道是应该承认和短路的东西吗?

If we also "over-expand" your other example:

  IO ( s0 -> let !(# s1, _ #)    = unIO (putStrLn "What is your name?") s0 in
              let !(# s2, name #) = unIO getLine s1 in
              let !(# s3, a3 #)   = unIO (putStrLn ("Nice to meet you, " ++ name ++ "!")) s2 in
              (# s3, a3 #))

我们可以清楚地看到,实际被忽视的是outputs。 - 即<代码>(>)


http://www.un.org/Depts/DGACM/index_chinese.htm

同样的<代码>(+),(-)(*),即使其类型相同()。 Num a => a -> a-> a - by with different name.





相关问题
Euler Problem in Haskell -- Can Someone Spot My Error

I m trying my hand at Euler Problem 4 in Haskell. It asks for that largest palindrome formed by multiplying two three-digit numbers. The problem was simple enough, and I thought my Haskell-fu was up ...

How does foldr work?

Can anybody explain how does foldr work? Take these examples: Prelude> foldr (-) 54 [10, 11] 53 Prelude> foldr (x y -> (x+y)/2) 54 [12, 4, 10, 6] 12.0 I am confused about these executions....

Efficient queue in Haskell

How can I efficiently implement a list data structure where I can have 2 views to the head and end of the list, that always point to a head a tail of a list without expensive calls to reverse. i.e: ...

Problem detecting cyclic numbers in Haskell

I am doing problem 61 at project Euler and came up with the following code (to test the case they give): p3 n = n*(n+1) `div` 2 p4 n = n*n p5 n = n*(3*n -1) `div` 2 p6 n = n*(2*n -1) p7 n = n*(5*n -3)...

Ways to get the middle of a list in Haskell?

I ve just started learning about Functional Programming, using Haskel. I m slowly getting through Erik Meijer s lectures on Channel 9 (I ve watched the first 4 so far) and in the 4th video Erik ...

haskell grouping problem

group :: Ord a => [(a, [b])] -> [(a, [b])] I want to look up all pairs that have the same fst, and merge them, by appending all the list of bs together where they have the same a and discarding ...

Closest equivalent to subprocess.communicate in Haskell

I want to do a popen() / python s subprocess.communicate from Haskell - start a program, give it stdin, and get its stdout/stderr. What s the most direct / Haskellish way to do this?