我一直在研究计算机程序的结构和解释,并完成Haskell的练习.前两章很好(github上的代码),但第3章让我更难思考.
首先是谈论管理国家,以银行账户为例.他们定义一个函数make-withdraw通过
(define (make-withdraw balance)
(lambda (amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds")))
Run Code Online (Sandbox Code Playgroud)
这样您就可以执行以下代码:
(define w1 (make-withdraw 100))
(define w2 (make-withdraw 100))
(w1 50)
50
(w2 70)
30
(w2 40)
"Insufficient funds"
(w1 40)
10
Run Code Online (Sandbox Code Playgroud)
我不确定如何在Haskell中模仿这个.我首先想到了一个使用State monad的简单函数:
import Control.Monad.State
type Cash = Float
type Account = State Cash
withdraw :: Cash -> Account (Either String Cash)
withdraw amount = state makewithdrawal where
makewithdrawal balance = if balance …Run Code Online (Sandbox Code Playgroud) 我正在寻找一种在ST-Monad中并行运行两个计算的方法.我正在构建一个相当大的数组(使用STUArray),我想并行执行.
到目前为止,我已经在stackoverflow上找到了这个和这个 Q&A,但是第一个不适用于我的情况,因为它只处理纯代码而第二个处理IO monad - 但我处于State Thread中.
我也找到了monad-parallel包,但它要求我为ST设置一个'MonadParallel'实例.另外,单子面值包中只支持纯计算或IO单子.
有没有办法在ST内进行并行monadic计算?
考虑以下:
do
x1 <- new 2
set x1 3
x2 <- get x1
y1 <- new 10
set y1 20
y2 <- get y1
return (x2 + y2)
Run Code Online (Sandbox Code Playgroud)
我想要这个结果23.有没有办法在纯Haskell中实现这样的东西,如果是这样的话怎么样?我理解STRef这样的事情,但我只是想在普通的Haskell中做到这一点(现在不担心效率).我认为我必须创建一个数据类型并使其成为实例Monad,但我不确定细节,所以一个有用的例子会有所帮助.
我试图通过移植Dan Piponi本教程中的一些例子来了解Scala中的Monad Transformers:http: //blog.sigfpe.com/2006/05/grok-haskell-monad-transformers.html
我做了几件简单的事:
import Control.Monad.State
import Control.Monad.Identity
test1 = do
a <- get
modify (+1)
b <- get
return (a,b)
test2 = do
a <- get
modify (++"1")
b <- get
return (a,b)
go1 = evalState test1 0
go2 = evalState test2 "0"
Run Code Online (Sandbox Code Playgroud)
变为:
import scalaz._, Scalaz._
val test1 = for {
a <- get[Int]
_ <- modify[Int](1+)
b <- get
} yield (a,b)
val test2 = for {
a <- get[String]
_ <- modify[String](_ + …Run Code Online (Sandbox Code Playgroud) 我是Haskell的新手并试图了解monad.我将通过此代码 将其放在这里以供快速参考
newtype State s a = State { runState :: s -> (a,s) }
instance Monad (State s) where
return a = State $ \s -> (a, s)
State act >>= k = State $ \s ->
let (a, s') = act s
in runState (k a) s'
get :: State s s
get = State $ \s -> (s, s)
put :: s -> State s ()
put s = State $ \_ -> ((), s)
modify …Run Code Online (Sandbox Code Playgroud) 我正在通过示例阅读Purescript并介绍了阅读Monad的部分.这个例子是这样的:
createUser :: Reader Permissions (Maybe User)
createUser = do
permissions <- ask
if hasPermission "admin" permissions
then map Just newUser
else pure Nothing
Run Code Online (Sandbox Code Playgroud)
对我来说令人困惑的部分是ask功能.签名是:
ask :: forall r. Reader r r
Run Code Online (Sandbox Code Playgroud)
它看起来好像是凭空创造了一个阅读器
当我读到Statemonad时,它的get功能与概念相同.文字解释说:
状态被实现为State monad的数据构造函数隐藏的函数参数,因此没有明确的引用传递.
我猜这是关键,同样的事情发生在这里与读者,但我不明白它是如何工作的......
当上面的例子运行时runReader,提供的值如何突然出现ask?Haskell文档ask说:检索monad环境.但我的困惑是从哪里来的?我看到它的方式,一个值传递给runReader,存储在某个地方,并得到它 - 你打电话ask......但这没有任何意义.
虽然这个例子是Purescript,但我猜测任何有Haskell识字的人也能够回答,因此Haskell标签.
我终于掌握了如何使用monads(不知道我是否理解它们......),但我的代码从来都不是很优雅.我想是因为缺乏对所有这些功能如何Control.Monad真正起作用的把握.所以我认为在使用状态monad的特定代码段中询问关于此的提示会很好.
代码的目标是计算多种随机游走,这是我在更复杂的事情之前尝试做的事情.问题是我同时有两个有状态计算,我想知道如何用优雅组合它们:
Seed -> (DeltaPosition, Seed)DeltaPosition -> Position -> (Log, Position)(Log我只能通过某种方式报告随机游走者的当前位置).我做的是这样的:
我有一个函数来组成这两个有状态的计算:
composing :: (g -> (b, g)) -> (b -> s -> (v,s)) -> (s,g) -> (v, (s, g))
composing generate update (st1, gen1) = let (rnd, gen2) = generate gen1
(val, st2) = update rnd st1
in (val, (st2, gen2))
Run Code Online (Sandbox Code Playgroud)
然后我把它变成一个组成状态的函数:
stateComposed :: State g b -> (b -> State s v) -> State (s,g) v
stateComposed rndmizer updater …Run Code Online (Sandbox Code Playgroud) 我正在尝试将Spider Solitaire播放器编写为Haskell学习练习.
我的main函数将为playGame每个游戏(使用mapM)调用一次函数,传入游戏编号和随机生成器(StdGen).该playGame函数应该返回一个Control.Monad.Statemonad和一个IO monad,其中包含一个String显示游戏画面并Bool指示游戏是赢还是输的.
如何将Statemonad与IOmonad 结合起来获得返回值?`playGame的类型声明应该是什么?
playGame :: Int -> StdGen a -> State IO (String, Bool)
Run Code Online (Sandbox Code Playgroud)
是对的State IO (String, Bool)吗?如果不是,它应该是什么?
在main,我计划使用
do
-- get the number of games from the command line (already written)
results <- mapM (\game -> playGame game getStdGen) [1..numberOfGames]
Run Code Online (Sandbox Code Playgroud)
这是正确的打电话playGame吗?
假设我有一个monadT:
type Wrap a = ReaderT Env ( StateT Int ( StateT Int Identity ) ) a
Run Code Online (Sandbox Code Playgroud)
这里要注意的重要一点是,一个StateT正在包装另一个,并且两者都包含在第三个MonadT内,即ReaderT.
以及相应的runWrap函数以方便:
type Env = Map.Map Char Integer
runWrap :: Env -> Int -> Int -> Wrap a -> a
runWrap env st1 st2 m = runIdentity $ evalStateT ( evalStateT ( runReaderT m env ) st2 ) st1
Run Code Online (Sandbox Code Playgroud)
一个通用的tock状态monad:
tock :: (Num s, MonadState s m) => m ()
tock = do modify (+1)
Run Code Online (Sandbox Code Playgroud)
我现在创建一个包裹monadT,其中我使用tock:
aWrap :: Wrap ( Int, Int ) …Run Code Online (Sandbox Code Playgroud) 有人可以展示一个简单的例子,其中状态monad可以比直接传递状态更好吗?
bar1 (Foo x) = Foo (x + 1)
Run Code Online (Sandbox Code Playgroud)
VS
bar2 :: State Foo Foo
bar2 = do
modify (\(Foo x) -> Foo (x + 1))
get
Run Code Online (Sandbox Code Playgroud) haskell ×10
state-monad ×10
monads ×6
io ×1
purescript ×1
reader-monad ×1
scala ×1
scalaz ×1
sicp ×1
state ×1