我知道ST monad就像是IO的小兄弟,后者又是带有RealWorld魔法的状态monad .我可以想象状态,我可以想象RealWorld以某种方式被放入IO,但每次我写一个ST monad 的类型签名都ST让s我感到困惑.
举个例子吧ST s (STArray s a b).s那里的工作如何?它是否仅用于在计算之间建立一些人工数据依赖性,而不能像状态monad中的状态那样被引用(由于forall)?
我只是抛出想法,真的很感谢比我更有知识的人向我解释.
每个其他monad都带有变压器版本,据我所知,变压器的概念是monad的通用扩展.跟随其他变形金刚的构建方式,IOT就像是
newtype IOT m a = IOT { runIOT :: m (IO a) }
Run Code Online (Sandbox Code Playgroud)
我可以在现场组成有用的应用程序:IOT Maybe可以执行IO操作,IOT []也可以不执行任何操作,可以构建一个稍后可以执行的列表sequence.
那么为什么Haskell中没有IO变压器呢?
(注意:我在Haskell Cafe上看过这篇文章,但对它没有多大意义.另外,ST转换器的Hackage页面在其描述中提到了一个可能相关的问题,但没有提供任何细节.)
我无法理解Haskell(GHC)如何编译程序,以及这些程序是如何运行的.
可能重复:
用GHC编译成小二进制的小Haskell程序
最近我注意到Haskell可执行文件有多大.下面的所有内容都是-O2在Linux 上用GHC 7.4.1编译的.
Hello World(main = putStrLn "Hello World!")超过800 KiB.strip在它上面运行会将文件大小减少到500 KiB; 甚至添加-dynamic到编译中也没有多大帮助,让我在400 KiB附近删除了一个可剥离的可执行文件.
编译涉及Parsec的非常原始的示例产生1.7 MiB文件.
-- File: test.hs
import qualified Text.ParserCombinators.Parsec as P
import Data.Either (either)
-- Parses a string of type "x y" to the tuple (x,y).
testParser :: P.Parser (Char, Char)
testParser = do
a <- P.anyChar
P.char ' '
b <- P.anyChar
return (a, b)
-- Parse, print result.
str = "1 2"
main = print $ …Run Code Online (Sandbox Code Playgroud)为什么Haskell中有两个不同的Writer类型monad?直觉上,读"严格的作家monad"意味着<>严格,所以日志中没有thunk积累.但是,查看源代码,事实证明并非如此:
-- Lazy Writer
instance (Monoid w, Monad m) => Monad (WriterT w m) where
-- ...
m >>= k = WriterT $ do
~(a, w) <- runWriterT m
~(b, w') <- runWriterT (k a)
return (b, w <> w')
Run Code Online (Sandbox Code Playgroud)
在严格的版本中,模式不是无可辩驳的,即~缺失.所以上面发生的是,m并且k a没有评估,但存储为thunk.在严格版本中,它们被评估以检查它们是否与元组模式匹配,结果被馈送到<>.在这两种情况下,在>>=实际需要产生的值之前不会对其进行评估.所以我理解它的方式是懒惰和严格版本都做同样的事情,除了它们在定义中的不同位置有thunk >>=:lazy产生runWriterTthunks,strict产生<>thunk.
这让我有两个问题:
<>不编写自己的包装器和实例的情况下完成严格吗?(在我开始之前:我将使用Cabal for Everything,其名称中包含Cabal并与Haskell有关.)
有了通常的"你需要更新X来安装Y,但这会打破依赖性Z"问题,前几天,我想我只是问:为什么Cabal不是设计成一个完整的包管理器,特别是以下功能:
你会看到这个列表的去向.现在,对我来说,Cabal感觉就像一个有点复杂的构建系统(当你想第一次开始使用它时,试着找出你的软件包所需的Base版本),这是一个半生不熟的软件包安装程序.
所以问题再次出现:为什么Cabal没有制作全功能的构建/包装系统?我确信有一些设计决定导致当前状态.
(这个问题在某种程度上受到了对Reddit的咆哮的启发,但与那个人相反并不意味着冒犯任何人.):-)
我有一个返回IO动作的函数,
f :: Int -> IO Int
Run Code Online (Sandbox Code Playgroud)
我想为参数的多个值并行计算这个函数.我天真的实施如下:
import Control.Parallel.Strategies
vals = [1..10]
main = do
results <- mapM f vals
let results' = results `using` parList rseq
mapM_ print results'
Run Code Online (Sandbox Code Playgroud)
我给这理由是,第一mapM结合型的东西IO [Int]来results,results'应用并行的策略所包含的名单,并mapM_通过打印,最后请求的实际值-但究竟是要打印并行已经引起的,所以程序应并行.
在确实使用了我所有的CPU之后感到高兴,我注意到程序在运行时效果较差(如挂钟时间),而+RTS -N8不是没有任何RTS标志.我能想到的唯一解释是,第一个mapM必须排序 - 即执行 - 所有IO操作已经,但这不会导致无效,但使N8执行与非平行的一样有效,因为所有的工作都由主线程.以+RTS -N8 -s收益率运行程序SPARKS: 36 (11 converted, 0 overflowed, 0 dud, 21 GC'd, 4 fizzled),这肯定不是最优的,但不幸的是我无法理解它.
我想我已经在Haskell并行化或IO monad的内部找到了初学者的垫脚石之一.我究竟做错了什么?
背景信息:f n是一个返回Project Euler问题n的解决方案的函数.由于其中许多都有要读取的数据,因此我将结果放入IO monad中.它看起来如何的一个例子是 …
QuickCheck的Batch模块已被删除,版本2(1.2.0.1仍然有它).因此,我总是觉得 - mapM_在一起进行多项测试是一种hacky.我是否忽略了QuickCheck 2中的后续功能?是否存在将独立测试组合在一起的规范方法?
在查看文档时Data.Set,我看到在树中插入元素被称为O(log(n)).但是,我会直观地期望它是O(n*log(n))(或者可能是O(n)?),因为参照透明度需要在O(n)中创建前一个树的完整副本.
据我所知,例如(:)可以将O(1)代替O(n),因为这里不必复制完整列表; 新的列表可以由编译器优化为第一个元素加上指向旧列表的指针(请注意,这是一个编译器 - 而不是语言级别 - 优化).但是,在a中插入一个值Data.Set涉及重新平衡,这对我来说非常复杂,我怀疑有类似于列表优化的东西.我尝试阅读Set docs引用的论文,但无法用它来回答我的问题.
那么:如何在一个(纯)函数式语言中将元素插入二叉树中是O(log(n))?
haskell ×10
monads ×4
compilation ×2
ghc ×2
io ×2
cabal ×1
free-monad ×1
quickcheck ×1
runtime ×1
writer ×1