【发布时间】:2020-03-18 19:44:55
【问题描述】:
注意:这是一个练习,我试图了解事情是如何运作的。
我试图让在 Haskell 中做这样的事情成为可能:
f :: Integer -> Integer
f n = def $ do
i <- var n
while i (>0) $ do
i -= lit 1
return i
-- for now, my program returns n
下面是我的程序。在这一点上,我不明白为什么它不起作用,但由于某种原因,变量没有改变。
import Control.Monad.State
data Lit a = Lit a
type Variable a = State Integer a
def :: Variable (Lit a) -> a
def (State f) = fromLit . fst . f $ 0
fromLit :: Lit a -> a
fromLit (Lit a) = a
lit :: a -> Lit a
lit l = Lit l
var :: a -> Variable (Lit a)
var v = State $ \x -> (lit v, x)
while :: Lit a -> (a -> Bool) -> Variable () -> Variable ()
while (Lit r) cond act = do
if cond r then do
_ <- act
while (Lit r) cond act
-- or act >> while (Lit r) cond act
else return ()
op :: (Integer -> Integer -> Integer) -> Lit Integer -> Lit Integer -> Variable ()
op f (Lit a) (Lit b) = State $ \n -> ((), if n == a then f a b else n)
-- that is, if the state is (a) change it to (f a b), else don't change it
(+=) = op (+)
(-=) = op (-)
(*=) = op (*)
请帮助我了解这里出了什么问题以及如何改进代码。谢谢。
【问题讨论】:
-
我不同意反对意见,我认为这是关于如何为命令式结构建模的一个很好的练习(好吧,只要你不将这种风格用于日常代码 :-))。无论如何,
State Integer不是一个合适的单子,除非你的命令式程序只使用一个变量。您可能需要State (VariableName -> Integer)或Map类似的以提高效率。为了提高效率,我会改用ST s。 -
@chi,这里的
VariableName是什么? -
它可以是
String,或者你想用于变量名的任何类型。原则上也可以使用Int。如果您愿意,可以改为使用“位置”或“参考”,因为您似乎使用var创建它们。
标签: haskell state-monad imperative