我开始理解forall
关键字如何在所谓的"存在类型"中使用,如下所示:
data ShowBox = forall s. Show s => SB s
Run Code Online (Sandbox Code Playgroud)
然而,这仅仅是如何forall
使用的一个子集,我根本无法将其用于这样的事情:
runST :: forall a. (forall s. ST s a) -> a
Run Code Online (Sandbox Code Playgroud)
或解释为什么这些是不同的:
foo :: (forall a. a -> a) -> (Char, Bool)
bar :: forall a. ((a -> a) -> (Char, Bool))
Run Code Online (Sandbox Code Playgroud)
或整个RankNTypes
东西......
我倾向于选择清晰,无术语的英语而不是学术环境中常见的语言.我尝试阅读的大部分解释(我可以通过搜索引擎找到的解释)存在以下问题:
runST
,foo
和bar
以上).所以...
关于实际问题.任何人都可以完全解释的forall
清晰,简单的英语关键字(或者,如果它存在于某个地方,点到我已经错过了这样一个明确的解释),不承担我在行话悠久的数学家?
编辑添加:
下面有高质量的答案有两个突出的答案,但不幸的是我只能选择一个最好的答案. 诺曼的回答很详细的和有用的,解释的方式,表现出一定的理论基础的东西forall
,并在同一时间向我展示了一些它的实际影响. yairchu的回答覆盖了其他人没有提到的范围(范围类型变量),并用代码和GHCi会话说明了所有概念.我愿意选择两者是最好的.不幸的是,我不能和上,俯瞰着两个答案后密切,我已经决定,yairchu的稍微挤掉了诺曼,因为说明性代码和附加的说明.这是一个有点不公平,但是,因为我真的需要这两个答案,了解这一点是一点forall
没给我留下了恐惧的隐隐感觉,当我看到它在类型签名.
就像背景一样,我知道Fisher-Yates完美的洗牌.它的O(n)复杂性和保证的一致性是一个很好的混乱,我不会使用它...在一个允许就地更新数组的环境中(所以在大多数情况下,如果不是全部,命令式编程环境).
可悲的是,函数式编程世界并没有让你访问可变状态.
然而,由于Fisher-Yates,我没有很多关于如何设计改组算法的文献.完全解决这个问题的几个地方之前做了这么简单的说法,实际上,"所以这里是Fisher-Yates,这是你需要知道的所有洗牌".最后,我必须提出自己的解决方案.
我想出的解决方案是这样的,可以随机播放任何数据列表:
在Erlang代码中,它看起来像这样:
shuffle([]) -> [];
shuffle([L]) -> [L];
shuffle(L) ->
{Left, Right} = lists:partition(fun(_) ->
random:uniform() < 0.5
end, L),
shuffle(Left) ++ shuffle(Right).
Run Code Online (Sandbox Code Playgroud)
(如果这看起来像是一种疯狂的快速排序,那么,基本上就是这就是它.)
所以这就是我的问题:同样的情况使得找到非Fisher-Yates 的改组算法变得困难,这使得找到分析混洗算法的工具同样困难.在分析PRNG的均匀性,周期性等方面,我可以找到很多文献,但没有关于如何分析洗牌的大量信息.(事实上,我在分析shuffle时发现的一些信息是完全错误的 - 很容易通过简单的技术欺骗.)
所以我的问题是:我如何分析我的改组算法(假设那里的random:uniform()
调用可以生成具有良好特性的适当随机数)?我可以使用哪些数学工具来判断,在1 ... 100的整数列表中,是否有100,000次洗牌运行给了我合理的改组结果?我已经做了一些我自己的测试(例如,比较增量到shuffles中的减量),但我想知道更多.
如果对该混洗算法本身有任何了解,也会受到重视.
这个问题与我关于Java中现有协程实现的问题有关.如果我怀疑,事实证明Java中目前没有完整的协同程序实现,那么实现它们需要什么?
正如我在那个问题中所说,我知道以下内容:
我将依次解决每个人的不足之处.
这种"解决方案"是病态的.协同程序的重点是避免线程,锁定,内核调度等的开销.协同程序应该是轻量级的,并且只能在用户空间中执行.在具有严格限制的全倾斜螺纹方面实现它们可以消除所有优点.
这种解决方案更实用,虽然有点难以实现.这与在C中的协同程序库中跳转到汇编语言大致相同(这是其中有多少工作),其优点是您只有一个架构可以担心并且正确.
它还将您绑定到仅在完全兼容的JVM堆栈上运行代码(例如,没有Android),除非您可以找到在非兼容堆栈上执行相同操作的方法.但是,如果您确实找到了这样做的方法,那么您现在已经将系统复杂性和测试需求翻了一番.
达芬奇机器很酷的实验,但由于它不是标准的JVM,它的功能无处不在.事实上,我怀疑大多数生产环境都会特别禁止使用达芬奇机器.因此,我可以使用它来进行很酷的实验,但不能用于我期望发布到现实世界的任何代码.
这也有类似于上面的JVM字节码操作解决方案的附加问题:将无法在替代堆栈(如Android)上工作.
这个解决方案在Java中实现这一点的意义重大.CPU和操作系统的每种组合都需要独立测试,每一种都是可能令人沮丧的微妙故障.或者,当然,我可以完全将自己绑定到一个平台,但这也使得用Java做事的意义完全没有实际意义.
所以...
有没有办法在不使用这四种技术之一的情况下在Java中实现协同程序?或者我会被迫使用那些闻起来最少的四个中的一个(JVM操作)?
编辑添加:
只是为了确保混乱载,这是一个相关的问题我的另外一个,但又不尽相同.那个人正在寻找一个现有的实施方案,以避免不必要地重新发明轮子.这是一个问题,如果另一个证明无法解决,将如何在Java中实现协同程序.目的是在不同的线程上保留不同的问题.
有许多片段详细说明了Erlang中解析变换过程的各个部分,但是我没有发现从动机到执行的完整覆盖.是否有一个很好的教程,我在某处遗漏了,如果有的话,它在哪里可以找到?
它们是不同的还是可以互换使用?如果它们不同,那么是什么使它们彼此不同?
我想用Java做一些事情,如果使用并发例程编写会更清楚,但是对于哪些完全线程严重过度杀伤.当然,答案是使用协同程序,但标准Java库中似乎没有任何协程支持,而快速谷歌在这里或那里会带来诱人的提示,但没有什么实质性的.
这是我到目前为止所发现的:
yield
只返回调用者的功能.正确的协同程序允许yield
s将控制权直接转移到任何已知的协程.基本上这个库,重量级和可怕的,只给你支持迭代器,而不是完全通用的协同程序.这就是我发现的一切.
我知道Da Vinci机器中对协同程序的本机JVM支持,我也知道这样做的JNI延续技巧.然而,对我来说这些并不是一个很好的解决方案,因为我不一定能控制我的代码运行在哪个VM或平台上.(事实上,任何字节码操作系统都会遇到类似的问题 - 如果可能的话,最好是纯Java.运行时字节码操作会限制我在Android上使用它.例如.)
那么有人有任何指针吗?这甚至可能吗?如果没有,是否可以在Java 7中使用?
编辑添加:
只是为了确保混乱载,这是一个相关的问题我的另外一个,但又不尽相同.这个是寻找现有的实施方案,以避免不必要地重新发明轮子.另一个是关于如何在Java中实现协同程序的问题,如果这个问题无法解决的话.目的是在不同的线程上保留不同的问题.
进一步编辑添加:
该答案被选中.然而,有些评论是有条理的.库指向的不是一个协程库,所以它在技术上不回答我的问题.尽管如此,它与上面链接的Google Code项目有两个优势:
由于副作用破坏了参考透明度,它们是否违背功能语言的观点?
今天我在接受采访时谈到了Java中的Thread概念?问题是......
除了Thread的定义之外,我没有回答任何问题,我也是从互联网上学到的.
任何人都可以清楚地向我解释这个.
更新:
线程和普通java类之间有什么区别.为什么我们需要线程...我可以在线程中执行业务逻辑.我可以在Threads中调用不同的类方法.
对于我正在制作的游戏,我有一个我有一个数字列表的情况 - 比如[7,4,9,1,15,2](以此命名A
) - 以及另一个数字列表 - 比如[11,18] ,14,8,3](命名B
) - 提供给我.我们的目标是找到所有数字组合A
,加上一个数字B
.例如:
...等等.(出于此目的,与之1 + 2
相同2 + 1
.)
对于像这样的小型列表,对组合进行暴力破坏是微不足道的,但是我面临着看到数千到数万这些数字的可能性,并将在应用程序的生命周期内重复使用这个例程.有没有任何一种优雅的算法可以在100%覆盖率的合理时间内完成此任务?如果不这样,我能找到任何一种体面的启发式方法,可以在合理的时间内给我一套"足够好"的组合吗?
我正在寻找伪代码或任何体面流行和可读语言的算法(注意"和"那里......;)甚至只是英文描述如何实现这种搜索.
编辑添加:
到目前为止提供了大量有用的信息.谢了,兄弟们!总结一下:
这可能是一个简单明了的事情,我只是没有看到,但如何在MIPS64处理器中加载地址?在MIPS32处理器中,以下汇编程序伪指令:
la $at, LabelAddr
Run Code Online (Sandbox Code Playgroud)
扩展到:
lui $at, LabelAddr[31:16]
ori $at,$at, LabelAddr[15:0]
Run Code Online (Sandbox Code Playgroud)
看一下MIPS64指令集,我看到lui
仍然会在32位字的上半部分加载一个16位立即数.似乎没有任何类型的扩展指令将立即加载到64位字的上部区域.那么,似乎要做一个la
伪指令的等价物,我需要扩展到代码中,例如:
lui $at, LabelAddr[63:48]
ori $at, $at, LabelAddr[47:32]
sll $at, 16
ori $at, $at, LabelAddr[31:16]
sll $at, 16
ori $at, $at, LabelAddr[15:0]
Run Code Online (Sandbox Code Playgroud)
这让我觉得有点......因为加载一个地址这样基本的东西令人费解,所以它让我确信我忽略了一些东西.
我忽略了什么(如果有的话)?