论坛首页 综合技术论坛

关于函数式编程中函数不产生副作用的困惑

浏览 9422 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-12-21  
FP
因为函数式编程的每一个符号都是 final 的,没有函数产生过副作用。因为从未在某个地方修改过值,也没有函数修改过在其作用域之外的量并被其他函数使用(如类成员或全局变量)。
我对这点有不理的地方。比如对于生产者,消费者问题,用函数式编程如何解决?因为没有类成员或全局变量可以被改变,那么用什么功能来表示那个容纳生产者生产出来的产品的容器呢?
最起码生产者身产了产品后需要改变容器的值,而消费者读取了容器的产品后也要改变容器的值。函数式编程的每一个符号都是 final 的是否意味着这个容器也是不可改变的?如果不可改变那么用函数式编程如何实现生产者,消费者问题?
   发表时间:2006-12-21  
这两种概念是正交的.
0 请登录后投票
   发表时间:2006-12-21  
虽然已知lambda等价图灵机,试试写一个出来还是很有意思的:
Producter.createProducter("producter 1").notify(message,Consumer.create("No.1"),Consumer.create("No.2")....)
define producter.nofiy:
    params.ifExist().next().invokeConsumeMessage(message).ifExist().next().invokeConsumMessage(message)...好变态!
0 请登录后投票
   发表时间:2006-12-21  
wolfsquare 写道
这两种概念是正交的.

麻烦讲的再清楚一些,木有看懂,谁和:函数不产生副作用是正交的。
你的代码也木有看懂:( 可以讲清楚点么?
0 请登录后投票
   发表时间:2006-12-21  
消息通信机制实现一个简单的生产者消费者问题,貌似复杂了点

-module(demo).
-export([main/0]).
-export([producer/2,consumer/1,queue/2]).

producer(QueuePid, Id) ->
	timer:sleep(500),
	QueuePid ! {produce, Id},
      io:format("Producer:Put Produce ~p~n", [Id]),
	producer(QueuePid, Id+1).

consumer(QueuePid) ->
	QueuePid ! {get_produce, self()},
	receive
		{produce, ProduceId} ->
			io:format("Consumer:Get Produce ~p~n", [ProduceId]);
		any -> ok
	end,
      timer:sleep(600),
	consumer(QueuePid).

queue(List, []) ->
    io:format("Queue:List is ~p~n", [List]),
	receive
		{produce, ProduceId} -> queue(List ++ [ProduceId], []);
		{get_produce, ConsumerPid} -> 
            case List of
                [] ->
                    queue([], [ConsumerPid]);
                [H|T] -> 
                    ConsumerPid ! {produce,H},
            		queue(T, [])
            end
	end;
queue([], WaitingConsumerPids) ->
    io:format("Queue:Waiting consumers size is ~p~n", [length(WaitingConsumerPids)]),
	receive
		{produce, ProduceId} ->
            [H|T] = WaitingConsumerPids,
            H ! {produce, ProduceId},
            queue([],T);
        {get_produce, ConsumerPid} -> queue([], WaitingConsumerPids ++ [ConsumerPid])
    end.

main() ->
	QueuePid = spawn(?MODULE, queue, [[], []]),
	spawn(?MODULE, consumer, [QueuePid]),
	spawn(?MODULE, producer, [QueuePid, 0]).

0 请登录后投票
   发表时间:2006-12-21  
这就是传说中的Erlang?
0 请登录后投票
   发表时间:2006-12-22  
对于命令式的优点,函数语言当然不会做事不管。在Haskel中,通过构造monad可以获得普通命令式的副作用功能。其中state monad就是很好的例子。

可以看看这里,描述state monad,且有一个示列程序:http://bbs.btant.com/thread-409-1-1.html
0 请登录后投票
   发表时间:2006-12-29  
没有副作用也就是不改变世界
0 请登录后投票
   发表时间:2007-06-07  
靠monad是一个有效率保证的手段。其实,在解决必须要改变状态的问题时,FP 采取的手段是:不停的产生新的、拥有已改变过属性的对象(此时原对象不变),然后利用函数的参数为此对象添加与原对象相同的名字(但二者不再同一层空间中),再去操作这个对象,如此反复(所以,正则尾递归是至关重要的)。
看起来这样做效率低下,但如果使用编译型的FP语言时会发现几乎没有性能损失(具体优化措施见《现代编译原理》一书),差别仅在于是用栈分配还是堆分配。
在解决IO问题上,Haskell为方便起见还是用了monad。但真正应该作的是,使用延续(不停地用上文中的方法绑定函数的编程风格):每一次I/O都返回下一次IO要用到的另一个函数。这样每个函数的状态都不变(支持等式推理,即函数的参数->值维持数学映射),整个IO过程却完成了。
0 请登录后投票
   发表时间:2007-07-18  
javavsnet 写道
因为函数式编程的每一个符号都是 final 的,没有函数产生过副作用。因为从未在某个地方修改过值,也没有函数修改过在其作用域之外的量并被其他函数使用(如类成员或全局变量)。
我对这点有不理的地方。比如对于生产者,消费者问题,用函数式编程如何解决?因为没有类成员或全局变量可以被改变,那么用什么功能来表示那个容纳生产者生产出来的产品的容器呢?
最起码生产者身产了产品后需要改变容器的值,而消费者读取了容器的产品后也要改变容器的值。函数式编程的每一个符号都是 final 的是否意味着这个容器也是不可改变的?如果不可改变那么用函数式编程如何实现生产者,消费者问题?


容器不可改变,但是可以被丢弃的,然后用新的容器替代它。
这个方式的关键是确定什么时候完全丢弃旧容器,这比较影响时间和空间效率。
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics