我是高级C/C++/Java /汇编程序员,我一直对纯函数式编程范例着迷.我不时尝试用它来实现一些有用的东西,例如,一个小工具,但我经常很快就会意识到我(以及我的工具)在非纯语言中会更快.这可能是因为我对命令式编程语言有更多的经验,我的头脑中有成千上万的idoms,模式和典型的解决方案.
这是其中一种情况.我已经好几次遇到它了,我希望你们能帮助我.
让我们假设我编写了一个模拟通信网络的工具.一个重要的任务是生成网络数据包.这一代非常复杂,由许多函数和配置参数组成,但最后有一个主函数,因为我发现它很有用,我总是记下签名:
generatePackets :: Configuration -> [Packet]
Run Code Online (Sandbox Code Playgroud)
但是,经过一段时间后,我注意到,如果数据包生成在生成过程的众多子函数之一中存在某种随机行为,那将会很棒.由于我需要一个随机数生成器(我也需要在代码中的其他位置),这意味着手动将几十个签名更改为类似的
f :: Configuration -> RNGState [Packet]
Run Code Online (Sandbox Code Playgroud)
同
type RNGState = State StdGen
Run Code Online (Sandbox Code Playgroud)
我理解这背后的"数学"必要性(没有状态).我的问题是更高的(?)级别:经验丰富的Haskell程序员将如何处理这种情况?什么样的设计模式或工作流程可以避免以后的额外工作?
我从未与经验丰富的Haskell程序员合作过.也许你会告诉我你永远不会写签名,因为你之后必须经常更改签名,或者你给所有的功能都是状态monad,"以防万一":)
我在Java中编写了一个非常愚蠢的测试类:
public class Vector3 {
public double x,y,z ;
public Vector3(double x, double y, double z) {
this.x=x ; this.y=y ; this.z=z ;
}
public Vector3 subst(Vector3 v) {
return new Vector3(x-v.x,y-v.y,z-v.z) ;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我想看看Java Hotspot JIT(Client VM build 23.7-b01)生成的代码.我使用了"-XX:+ PrintAssembly"选项和来自http://classparser.blogspot.dk/2010/03/hsdis-i386dll.html的hsdis-i386.dll
这是生成代码的有趣部分(我已经跳过了新对象的初始化.编辑:subst方法的代码).显然,ebx是"this"指针,而edx是指向参数的指针.
lds edi,(bad)
sti
adc BYTE PTR [ebx+8],al ;*getfield x
mov edx,DWORD PTR [esp+56]
lds edi,(bad) ; implicit exception: dispatches to 0x02611f2d
sti
adc BYTE PTR [edx+8],cl ;*getfield x
lds edi,(bad)
sti
adc BYTE PTR [ebx+16],dl …Run Code Online (Sandbox Code Playgroud) 我可能遗漏了一些非常明显的东西:如何在Kotlin中有效地过滤和迭代HashMap的条目?
我想做以下事情:
myMap.filterValues{ someCondition }.forEach { doSomethingWithTheEntry }
Run Code Online (Sandbox Code Playgroud)
如何避免创建中间对象?filterValues将创建一个HashMap,这里不需要它.
我当然可以写
myMap.forEach { if(someCondition) doSomethingWithTheEntry }
Run Code Online (Sandbox Code Playgroud)
但功能式过滤方法看起来更优雅.