You re broaching a very important subject in functional programming, that is, performing I/O. The way many pure languages go about it is by using embedded domain-specific languages, e.g., a sublanguage whose task it is to encode actions, which can have results.
例如,Haskell的操作时间预计我会确定一项名为main<>/code>的行动,由构成我的方案的所有行动组成。 其后,该手术会执行。 多数时候,在这样做时,它执行的是纯粹的法典。 从时间来看,运行时间将使用计算数据进行I/O,并将反馈数据反馈为纯代码。
You might complain that this sounds like cheating, and in a way it is: by defining actions and expecting the runtime to execute them, the programmer can do everything a normal program can do. But Haskell s strong type system creates a strong barrier between pure and "impure" parts of the program: you cannot simply add, say, two seconds to the current CPU time, and print it, you have to define an action that results in the current CPU time, and pass the result on to another action that adds two seconds and prints the result. Writing too much of a program is considered bad style though, because it makes it hard to infer which effects are caused, compared to Haskell types that tell us everything we can know about what a value is.
Example: clock_t c = time(NULL); printf("%d
", c + 2);
in C, vs. main = getCPUTime >>= c -> print (c + 2*1000*1000*1000*1000)
in Haskell. The operator >>=
is used to compose actions, passing the result of the first to a function resulting in the second action. This looking quite arcane, Haskell compilers support syntactic sugar that allows us to write the latter code as follows:
type Clock = Integer -- To make it more similar to the C code
-- An action that returns nothing, but might do something
main :: IO ()
main = do
-- An action that returns an Integer, which we view as CPU Clock values
c <- getCPUTime :: IO Clock
-- An action that prints data, but returns nothing
print (c + 2*1000*1000*1000*1000) :: IO ()
The latter looks quite imperative, doesn t it?