The*_*kle 7 haskell functional-programming side-effects referential-transparency
putStrLn
当使用任何参数调用时,将始终返回type的值IO ()
.我同意这是纯粹的,我可以处理.但它是否具有参考透明度?我是这么认为的,因为对于任何给定的输入,你可以用一个IO ()
将在stdout抛出正确字符串的函数调用替换.
所以我很酷putStrLn
,但是getLine
当没有参数调用时可以返回任何数量的东西,只要它们是类型的IO String
.这既不是纯粹的,也不是引用透明的吗?
愚蠢的迂腐问题,它可能不会改变我编写代码的方式,但我真的想要一劳永逸地解决这个问题.(我知道IO monad会正确排序,这不是我的问题)
这为我提出了另一个问题.编译器是否足够智能以识别不带输入的程序?比如说我编译
main = putStrLn . show $ map (+1) [1..10]
Run Code Online (Sandbox Code Playgroud)
GHC是否足够聪明,可以将该程序减少到IO ()
导致[2,3,4,5,6,7,8,9,10,11]打印出来的程序?或者它仍在运行并在运行时评估/执行所有内容?对于不需要输入的任意程序也是如此.GHC是否采用了这样一个事实:整个程序是透明的,并且可以简单地用它的价值取代?
我想这里有两个问题.
查看IO的类型,您可以想象它依赖于RealWorld
没有数据构造函数的神秘值,并通过使每个语句依赖于最后一个(在单个线程世界中)来模拟引用透明性.在a的情况下IO String
,这是一个newtype包装器RealWorld -> (RealWorld, String)
...这是一个函数,而不是一个值.在IO
没有Monad
实例的情况下使用会使这一点特别且痛苦地显而易见.
Prelude GHC.Types> :info IO
newtype IO a
= IO (GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, a #))
Run Code Online (Sandbox Code Playgroud)
至于GHC的优化,在这种情况下,它不会在编译时将列表减少为字符串.GHC 7.2.1生成的优化代码懒洋洋地生成一个列表,在结果上映射(+1),将列表转换为字符串,最后将其打印到控制台.几乎与它在您的示例中读取的完全相同.
是的,这些monadic函数是纯粹的引用透明的,因为替换规则仍然适用于它们.
在Haskell中,以下两个程序是等效的
main = (puStrLn "17" >> puStrLn "17")
main = let x = putStrLn "17" in (x >> x)
Run Code Online (Sandbox Code Playgroud)
在"正常"语言中,第二个例子只打印一次,作为评估的副作用x
.当你意识到类型的值IO()
实际上不是副作用计算但实际上是对这种计算的描述时,两个程序实际上是相同的方式变得更加清晰,你可以使用它作为构建块来构建更大的计算.
getLine :: IO String
是纯洁的; 它的值是IO动作,它从标准输入读取并返回*一个字符串.getLine
总是等于这个值.
*由于缺少更好的词,我在这里使用"返回"这个词.
维基百科将参照透明度定义为:
如果表达式可以替换为其值而不改变程序的行为(换句话说,产生在相同输入上具有相同效果和输出的程序),则表示该表达式是引用透明的.
所以getLine也是引用透明的.虽然我想不出以一种其他方式表达其"价值"的好方法,以"用它的价值取代表达".
另外,对于诸如" putStrLn
当使用任何参数调用时将始终返回IO ()
"之类的语句,应该有点小心.IO ()
是一种类型,而不是一种价值.对于每一个s :: String
,putStrLn s
都是类型的值IO ()
,是的.但是,这个价值s
当然取决于.
(此外,如果你排除这些unsafe
东西,一切都是纯粹的和引用透明的,尤其是那样getLine
.)
归档时间: |
|
查看次数: |
693 次 |
最近记录: |