问题描述
很简单的一个问题,、在Haskell中实现下面Lisp代码的功能。唉,Haskell啊,纯函数式啊,Monad啊,我刚学啊,不知道怎么办啊 (define inc (n) (lambda (i) (incf n i))) 问题补充:cloverprince 写道
解决方案
真的?但是我曾经发现,用Haskell写的一些代码,长度仅有等价的C或者Python代码的一半。比如这个,高阶函数和List Comprehension比循环简洁的多http://cloverprince.iteye.com/blog/319072但是,真正成问题的是,我不够聪明,以至于有时候我无法指出如何写出精简的代码。
解决方案二:
可以使用haskell的lambda实现,如下即可:inc n = i -> incf n i
解决方案三:
可以使用haskell的lambda实现,如下即可:inc n = i -> incf n i
解决方案四:
试试转换一下思维,能用命令式实现的一定能够用函数式方法实现。
解决方案五:
Haskell里变量是不可变的。函数是没有副作用的。所以,不可能去修改一个变量的值。其实,你的意思是,“调用”一个函数的时候,和某个符号(变量名)x相关的状态被改变;下次调用另一个函数,而且这个函数需要依赖于这个变量x,那么这个函数将返回不同的值。这样也做不到,因为既然是“函数”,那么给定相同的自变量,返回的值总是相同的,否则就不是“函数”了。可以用State monad模拟这种行为。实际上GHC已经包含了State这种类型。可以参考这个:http://www.haskell.org/haskellwiki/State_Monad,说实话,不太直观,但后面介绍了标准库的用法。下面是一个简单的实现。我们假设状态是Int型,定义为StateType。我们定义一种容器:保存一个值,附带当前的状态。就是那个ValueWithState。所谓“当前状态”,就是那个可以随便改变的Int值。然后定义一个Action,里面存了一个函数,输入旧状态,输出一个值和一个新状态。可以认为Action就是一步“操作”(可以和之前所有的运算结果相关),同时这步操作可能会改变当前状态。也就理解成“可能会发生副作用的操作”。我们定义几个特殊操作第一个是return x。函数return输入变量x产生一个操作,产生的这个操作不改变状态,但是会改变“当前值”,且“当前值”就是x。第二个是set n。这个操作会直接把当前状态改成n,但是这个操作本身不返回新的值。这里不得不让它返回()。第三个是get。这个操作会把“当前状态”放到“当前值”里,也就是“读取那个隐藏的状态”。然后就是add n了。其实有get和set就能随意改变“状态”了,加上这个add比较方便,就是把当前状态增加一些,不返回值(返回())。然后,为了让它成为Monad,我们必须允许把两个“Action”捆绑在一起,让它们看上去像一个Action。(注意,第二个Action可能依赖于第一个Action的运行结果,所以>>=的定义是 Monad a -> (a -> Monad b) -> Monad b)实现Monad要求的>>=函数,就是把“把两个Action捆绑起来”装得像一点。稍微有点麻烦。“完成两部操作”,就是:首先,在已知初始状态state0的情况下,完成第一步操作。然后,利用第一步操作的结果value1,制造出第二个操作(因为第二个操作可能依赖第一个)。然后已知第一步操作后的状态state1的条件下,执行第二个操作。这样得到的新值和新状态就是整体执行的结果了。然后就可以尽情地用do notation执行一些“看上去像命令式”的过程了。module Main wheretype StateType = Intdata ValueWithState valueType = ValueWithState StateType valueType deriving Showdata Action resultType = Action { doAction :: StateType -> (ValueWithState resultType)}get = Action { doAction = oldState -> ValueWithState oldState oldState}set n = Action { doAction = oldState -> ValueWithState n ()}addOne = Action { doAction = oldState -> ValueWithState (oldState+1) ()}add n = Action { doAction = oldState -> ValueWithState (oldState+n) ()}instance Monad Action where return result = Action { doAction = oldState -> ValueWithState oldState result } action1 >>= f = Action { doAction = state0 -> let ValueWithState state1 value1 = doAction action1 state0 action2 = f value1 ValueWithState state2 value2 = doAction action2 state1 in ValueWithState state2 value2 }someAction = do add 3 s1 <- return "Hello" add 2 s2 <- return "World" s3 <- get return (s1 ++ s2 ++ (show s3))ValueWithState finalState finalValue = doAction someAction 42main = do putStrLn (show finalState) putStrLn finalValue