任何人都可以得到一些指针为什么不纯计算在Haskell是按照作为异常?

我的意思是单只是一个界面与4个业务,那么,什么是推理模型侧重效果吗?

有帮助吗?

解决方案

假设一个功能有的副作用。如果我们采取所有影响其产生的输入和输出参数,那么功能是纯粹为外面的世界。

因此,对于不纯的功能

f' :: Int -> Int

我们添加实际的考虑

f :: Int -> RealWorld -> (Int, RealWorld)
-- input some states of the whole world,
-- modify the whole world because of the side effects,
-- then return the new world.

然后 f 是纯净的。我们确定了参数化的数据类型 IO a = RealWorld -> (a, RealWorld), 所以我们不需要种类型实际这么多次

f :: Int -> IO Int

程序员,处理实际直接在是太危险--特别是,如果一个程序员获取他们的手一个值的类型实际上,他们可能尝试 复制 它,它基本上是不可能的。(思考试图复制整个文件系统为例。你会在哪里呢?) 因此,我们定义的IO封装了该国的整个世界。

这些不纯粹的功能是无用的,如果我们不能把它们连在一起。考虑

getLine :: IO String               = RealWorld -> (String, RealWorld)
getContents :: String -> IO String = String -> RealWorld -> (String, RealWorld)
putStrLn :: String -> IO ()        = String -> RealWorld -> ((), RealWorld)

我们希望得到一名从控制台,请阅读该文件,然后打印内容。我们将如何做到这一点,如果我们可以访问的真实世界的国家?

printFile :: RealWorld -> ((), RealWorld)
printFile world0 = let (filename, world1) = getLine world0
                       (contents, world2) = (getContents filename) world1 
                   in  (putStrLn contents) world2 -- results in ((), world3)

我们看到一个模式:该职能被称为是这样的:

...
(<result-of-f>, worldY) = f worldX
(<result-of-g>, worldZ) = g <result-of-f> worldY
...

这样我们就可以定义的一个操作员 ~~~ 绑定:

(~~~) :: (IO b) -> (b -> IO c) -> IO c

(~~~) ::      (RealWorld -> (b, RealWorld))
      -> (b -> RealWorld -> (c, RealWorld))
      ->       RealWorld -> (c, RealWorld)
(f ~~~ g) worldX = let (resF, worldY) = f worldX in
                        g resF worldY

然后我们可以简单地写信

printFile = getLine ~~~ getContents ~~~ putStrLn

而不触及真正的世界。


现在假设我们想要使文件的内容大写。大写是一个纯粹的功能

upperCase :: String -> String

但是,要使它成为真正的世界,它必须返回 IO String.很容易升这样一个功能:

impureUpperCase :: String -> RealWorld -> (String, RealWorld)
impureUpperCase str world = (upperCase str, world)

这可以被笼统化:

impurify :: a -> IO a

impurify :: a -> RealWorld -> (a, RealWorld)
impurify a world = (a, world)

这样, impureUpperCase = impurify . upperCase, 我们可以写信

printUpperCaseFile = 
    getLine ~~~ getContents ~~~ (impurify . upperCase) ~~~ putStrLn

(注:通常情况下,我们写信 getLine ~~~ getContents ~~~ (putStrLn . upperCase))


现在让我们看看我们做了什么:

  1. 我们定义的一个操作员 (~~~) :: IO b -> (b -> IO c) -> IO c 这链条的两个不纯的功能结合在一起
  2. 我们定义的一个函数 impurify :: a -> IO a 它把一个纯粹的价值不纯。

现在我们做的识别 (>>=) = (~~~)return = impurify, 和看到的?我们已经有了一个单.


(检查是否这真的是一个单有几公理应得到满足:

(1) return a >>= f = f a

  impurify a               = (\world -> (a, world))
 (impurify a ~~~ f) worldX = let (resF, worldY) = (\world -> (a, world)) worldX 
                             in f resF worldY
                           = let (resF, worldY) =            (a, worldX))       
                             in f resF worldY
                           = f a worldX

(2) f >>= return = f

  (f ~~~ impurify) a worldX = let (resF, worldY) = impuify a worldX 
                              in f resF worldY
                            = let (resF, worldY) = (a, worldX)     
                              in f resF worldY
                            = f a worldX

(3) f >>= (\x -> g x >>= h) = (f >>= g) >>= h

行使。)

其他提示

任何人都可以得到一些指针为什么不纯计算在Haskell模拟作为单子?

这个问题包含一个普遍的误解。杂和单是独立的概念。杂质 建模的单.相反,有几个数据类型,例如 IO, ,这表示必须计算。而对于一些类型,其中一小部分他们的接口相对应的接口模式称为"单".此外,没有已知的纯的/职能/denotative解释 IO (并且有可能不一,考虑的 "罪孽站" 目的 IO),虽然没有通常所说的故事 World -> (a, World) 正的含义 IO a.这个故事不能如实地描述 IO, 因为 IO 支持并发和不确定性.故事甚至不工作的时候,对于确定性的计算,允许中期计算的相互作用的世界。

为更多的解释,请参阅 这个答案.

编辑:在重新阅读问题,我不认为我的回答是相当的轨道上。模型的必要计算做往往是单元,正如问题所述。Asker可能不是真的假设monadness以任何方式使模型的必要的计算。

我的理解是,有人称为 Eugenio Moggi 首先注意到,以前掩盖数学建造称为"单"可用于模式的副作用在计算机语言,因而指定他们的语义使用氧微积分。当Haskell,正在制订有各种方法中的不纯的计算模拟(见西蒙*佩顿*琼斯 "头发的衬衫"纸 更多的细节),但当时菲利浦wadler引元它迅速成为明显,这是答案。剩下的是历史。

任何人都可以得到一些指针为什么不纯计算在Haskell模拟作为单子?

嗯,因为Haskell是 纯粹的.你需要一个数学概念之间的区分 不纯的计算纯种者类型级别的 并模型 programm流 在分别。

这意味着你必须要结束了与某些类型 IO a 该模型的一个不纯的计算。然后你需要知道方式 相结合 这些计算的其 申请的顺序 (>>=)和 升值 (return)是最明显和最基本的。

这两个,你已经界定一个单 (甚至没有考虑它的);)

此外,单元提供 非常一般性的和强大的抽象, ,所以许多种类的控制流动可以便利普遍,在一元的职能喜欢 sequence, liftM 或特殊法,使unpureness不是这样的特殊情况。

看看 单元在编程功能唯一打字 (唯一的选择我知道)的更多信息。

正如你所说,Monad是一个非常简单的结构。答案的一半:Monad是这是我们可能给副作用的功能,并能够使用它们的最简单的结构。随着Monad我们可以做两件事情:我们可以把一个纯粹的价值作为一个副作用的值(return),我们可以应用副作用的功能,一个副作用的价值得到新的副作用的值(>>=) 。失去做任何的这些东西是沉重的,所以我们的副作用的类型必须是“至少” Monad的能力,而且事实证明Monad是否足以执行一切我们需要这么远。

另一半是:什么是最详细的结构,我们可以给“可能出现的副作用”?我们当然可以考虑为一组(需要是加入的唯一操作)的所有可能的副作用的空间。我们可以做他们一个接一个组合两个副作用,而这将产生不同的副作用(或可能的同一个 - 如果第一个是“关闭计算机”,第二是“写入文件”,那么结果构成的这些仅仅是“关闭计算机”)。

好了,我们能说这个手术?这是联想;也就是说,如果我们将三个副作用,不要紧,我们做这才能在结合。如果我们这样做(写文件然后读取插座),然后关闭电脑,这是一样的做写入文件,然后(读插座,然后关机电脑)。但它不是可交换:(“写文件”,然后“删除文件”)从(“删除文件”,然后“写文件”)不同的副作用。此外,我们还有一个身份:“集团”的特殊副作用“无副作用”的作品(“无副作用”,然后“删除文件”是相同的副作用,只是“删除文件”)在这一点上任何数学家正在思考但集团有逆,而且也没有办法反转一般的副作用; “删除文件”是不可逆的。因此,我们已经离开了结构是一个独异,这意味着我们的副作用的功能应该是单子。

是否有一个更复杂的结构?当然!我们可以划分可能出现的副作用为基于文件系统的影响,基于网络的影响多,而且我们可以拿出的组成更复杂的规则,保留这些细节。但同样它归结为:Monad很简单,但功能强大,足以表达我们最关心的性能。 (具体地,可结合,而另一个公理让我们测试在小块应用,与置信度的组合应用的副作用将是相同的片的副作用的组合)。

这实际上是相当的功能性的方式去思考的I / O干净的方式。

在大多数编程语言中,你做输入/输出操作。在Haskell,想象写代码不是的的操作,但产生的操作的列表,你会喜欢做的事。

单子只是相当语法这一点。

如果你想知道为什么单子,而不是别的东西,我想答案是,他们代表的是人们能想到,当他们做的Haskell的I / O的最佳功能性的方式。

AFAIK,原因是能够以包括类型系统副作用检查。如果您想了解更多,听那些 SE-无线电情节: 情节108:在函数式编程和Haskell西蒙·佩顿 - 琼斯 插曲72:埃里克·梅蒂赫尔上LINQ

上面还有与理论背景非常好详细的解答。但是,我想给我的单子IO看法。我没有经历过的Haskell程序员,所以可能这是很幼稚的,甚至是错误的。但是,我帮我处理IO单子在一定程度上(注意,这不涉及到其他的单子)。

首先,我想说的是,与“现实世界”这个例子是不是对我来说太清楚,因为我们不能访问它的(现实世界)之前的状态。可能是它不涉及在所有单子计算,但期望在引用透明感,这通常是在Haskell代码呈现。

因此,我们希望我们的语言(哈斯克尔)是纯的。但是,我们需要输入/输出操作因为没有他们我们的程序不能是有用的。而这些操作不能根据其性质纯粹。因此,只有这样,才能解决这个问题,我们必须不纯的操作从代码的其余部分分开。

下面单子来。其实,我不知道,有不能存在其他结构具有类似需要的属性,但问题是,单子具有这些特性,所以可以使用(可以成功使用)。其主要特性是,我们无法逃避它。 Monad的接口没有操作摆脱围绕我们的价值的单子。其他(未IO)单子提供这样的操作,并允许模式匹配(例如也许),但这些操作是不是在单子接口。另一所需性能是能力链运作。

如果我们想想我们在系统类型方面的需要,我们得出的事实是,我们需要构造,可以围绕任何谷包裹类型。构造函数必须是私有的,因为我们都禁止它(即,模式匹配)逃逸。但是,我们需要的功能把价值这个构造(这里返回想到)。而我们需要的方式,以连锁经营。如果我们考虑了一段时间,我们会来一个事实,即链接操作必须有类型为>> =有。所以,我们来非常相似单子的东西。我想,如果我们现在分析这个结构可能相互矛盾的情况下,我们会来单子公理。

请注意,所开发结构没有什么共同点有杂质。它只有性质,这是我们希望有能够应付不纯的操作,即不转义,链接和方式来获得。

现在一些不纯的集合操作的是由该被选择的单子IO内的语言预定义。我们可以结合这些操作来创建新的unpure操作。而所有这些操作将必须有IO在其类型。但是请注意,IO的类型中的一些功能是存在不使该功能不纯。但据我了解,这是不好的主意,写有IO纯函数在其类型,因为它是最初我们的想法来分离纯不纯功能。

最后,我想说,那单子不要把不纯操作成纯的。它只允许他们有效地分离。 (我重复,这是我的唯一的理解)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top