如何在函数式编程中增加变量

Ger*_*ens 17 haskell functional-programming

如何在函数式编程语言中增加变量?

例如,我想这样做:

main :: IO ()
main = do
    let i = 0
    i = i + 1
    print i
Run Code Online (Sandbox Code Playgroud)

预期产量:1.

Wil*_*ess 22

简单的方法是引入变量名称的阴影:

main :: IO ()                  -- another way, simpler, specific to monads:
main = do                         main = do
    let i = 0                         let i = 0
    let j = i                         i <- return (i+1)
    let i = j+1                       print i
    print i                    -- because monadic bind is non-recursive
Run Code Online (Sandbox Code Playgroud)

打印1.

只是写入let i = i+1不起作用,因为let在Haskell中进行递归定义 - 它实际上是Scheme的letrec.该i在右边let i = i+1是指i在其左侧- 给上一级i的可能意.所以我们通过引入另一个变量来打破这个等式j.

另一种更简单的方法是 <-do-notation 中使用monadic bind.这是可能的,因为monadic绑定不是递归的.

在这两种情况下,我们都会引入同名的变量,从而"遮蔽"旧实体,即使其不再可访问.

如何"思考功能"

这里要理解的一件事是,使用纯不可变值的函数式编程(就像我们在Haskell中所做的那样)迫使我们在代码中明确时间.

在命令式设置时间是隐含的.我们"改变"我们的变量 - 但任何变化都是连续的.我们永远不能改变什么VAR 刚才-它只是什么将是从现在开始.

在纯函数式编程中,这只是明确的.这可以采用的最简单的形式之一是使用值列表作为命令式编程中的顺序变化的记录.更简单的是使用不同的变量来表示实体在不同时间点的不同值(参见静态单一赋值形式或SSA).

因此,我们不是"改变"那些无法真正改变的东西,而是制作它的增强副本,然后传递,用它代替旧的东西.


Pro*_*bie 6

作为一般规则,你不(并且你不需要).但是,为了完整性的利益.

import Data.IORef
main = do
    i <- newIORef 0       -- new IORef i
    modifyIORef i (+1)    -- increase it by 1
    readIORef i >>= print -- print it
Run Code Online (Sandbox Code Playgroud)

但是,任何说你需要使用像MVar,IORef,STRef等的答案都是错误的.有一种纯粹的功能性方法,在这个小的快速编写的例子中看起来并不是很好.

import Control.Monad.State
type Lens a b = ((a -> b -> a), (a -> b))
setL = fst
getL = snd
modifyL :: Lens a b -> a -> (b -> b) -> a
modifyL lens x f = setL lens x (f (getL lens x))
lensComp :: Lens b c -> Lens a b -> Lens a c
lensComp (set1, get1) (set2, get2) =         -- Compose two lenses
    (\s x -> set2 s (set1 (get2 s) x)        -- Not needed here
     , get1 . get2)                          -- But added for completeness

(+=) :: (Num b) => Lens a b -> Lens a b -> State a ()
x += y = do
    s <- get
    put (modifyL x s (+ (getL y s)))

swap :: Lens a b -> Lens a b -> State a ()
swap x y = do
    s <- get
    let x' = getL x s
    let y' = getL y s
    put (setL y (setL x s y') x')

nFibs :: Int -> Int
nFibs n = evalState (nFibs_ n) (0,1)

nFibs_ :: Int -> State (Int,Int) Int
nFibs_ 0 = fmap snd get -- The second Int is our result
nFibs_ n = do
    x += y       -- Add y to x
    swap x y     -- Swap them
    nFibs_ (n-1) -- Repeat
  where x = ((\(x,y) x' -> (x', y)), fst)
        y = ((\(x,y) y' -> (x, y')), snd)
Run Code Online (Sandbox Code Playgroud)

  • 因为问题是如何在函数式编程语言中做i = i + 1.简单地说你不能或不应该是无益的. (4认同)