众所周知,Haskell风格的类型类和ML风格的模块提供了不同的指定接口的机制.它们(可能)具有相同的功率,但实际上每种都有其自身的优点和缺点.
由于我在语言功能方面有点像包容性,我的问题是:在Haskell中添加ML样式模块有哪些主要的理论上的困难?我对以下几行的答案感兴趣:
现有的类型系统功能与ML型模块的交互性很差?(不良交互的一个例子是GADT和功能依赖,即使fundeps在技术上等同于相关类型!)
为了编译ML样式的模块,必须在编译器端放弃什么?
ML样式模块如何与类型推断交互?
相关阅读:
我的问题是,标准ML的模块系统和OCaml模块系统之间是否有任何区别?OCaml是否有所有对仿函数,归属等的支持...... SML有哪些?
这个问题始于
SML.NET可以做仿函数并使用Microsoft .NET.
*请参阅:SML.NET用户指南第4.8.2节类类型和仿函数?
由于Microsoft .NET的一些限制,我一直看到F#无法做真正的仿函数.
*ML仿函数可以用.NET完全编码(C#/ F#)吗?
*算子的任何解决方法?
那么如果SML.NET可以在.NET上运行仿函数那么为什么F#不能呢?SML.NET做了什么,F#不能做什么?
我越了解来自类别理论的仿函数,我越看到它们的美丽,并希望在F#中拥有它们.
编辑
我注意到,在我知道的OCaml程序员中,他们中的一些总是使用多态变体(未声明的变体,以反引号为前缀),而其他变体从不使用多态变体,而更喜欢在类型中声明的变体.
除了性能原因(多态变体目前编译效率低于简单变体),专家OCaml开发人员如何在它们之间进行选择?
在"任意等级类型的实用类推理"中,作者讨论了包含:
我尝试在GHCi中测试的东西,但是即使g k2
是为了进行类型检查,当我尝试使用GHC 7.8.3时也不会:
?> :set -XRankNTypes
?> let g :: ((forall b. [b] -> [b]) -> Int) -> Int; g = undefined
?> let k1 :: (forall a. a -> a) -> Int; k1 = undefined
?> let k2 :: ([Int] -> [Int]) -> Int; k2 = undefined
?> :t g k1
<interactive>:1:3: Warning:
Couldn't match type ‘a’ with ‘[a]’
‘a’ is a rigid type variable bound by
the type forall a1. a1 …
Run Code Online (Sandbox Code Playgroud) 我已经在函数式语言中看到很多关于处理列表和构造函数的函数,这些函数在接收到一些额外的值(通常在生成函数时不存在)时对其元素执行某些操作,例如:
("懒惰评估"下的最后两个例子)
暂存列表以严格的函数语言(如ML/OCaml)附加,以避免多次遍历第一个列表
(标题为"暂存"的部分)
使用foldr将列表与另一个列表进行比较(即生成将另一个列表与第一个列表进行比较的函数)
listEq a b = foldr comb null a b
where comb x frec [] = False
comb x frec (e:es) = x == e && frec es
cmp1To10 = listEq [1..10]
Run Code Online (Sandbox Code Playgroud)在所有这些例子中,作者通常只注意遍历原始列表一次的好处.但是我不能让自己不要"确定,而不是遍历N个元素列表,而是遍历一系列N个评估,那又怎么样?".我知道必须有一些好处,有人可以解释一下吗?
编辑:感谢两者的答案.不幸的是,这不是我想知道的.我会试着澄清我的问题,所以它并没有与(更常见的)关于创建中间列表(我已经在不同的地方读过)相混淆.还要感谢我纠正我的帖子格式.
我对构造要应用于列表的函数的情况感兴趣,在该列表中,您还没有必要的值来评估结果(无论是否为列表).然后,您无法避免生成对每个列表元素的引用(即使列表结构不再被引用).并且您拥有与以前相同的内存访问权限,但您不必解构列表(模式匹配).
例如,请参阅上述ML书中的"分段"章节.我在ML和Racket中尝试过它,更具体地说是"追加"的阶段版本,它遍历第一个列表并返回一个函数,在尾部插入第二个列表,而不会多次遍历第一个列表.令我惊讶的是,即使考虑到它仍然必须复制列表结构,因为最后一个指针在每种情况下都不同,所以它要快得多.
以下是map的变体,应用于列表后,更改函数时应该更快.由于Haskell不严格,我将不得不强制评估listMap [1..100000]
in cachedList
(或者可能不是,因为在第一次应用之后它应该仍然在内存中).
listMap = foldr comb (const [])
where comb x rest = \f -> f x : rest f
cachedList = listMap [1..100000]
doubles = cachedList (2*)
squares = cachedList (\x -> …
Run Code Online (Sandbox Code Playgroud) 我必须在ML中编写一些代码,这是我第一次使用该语言.标准ML是否有任何开发环境?(最好在Windows下).我尝试使用googling(和stackOverFlowing!),但我发现的只是Linux的简单编译器(最多使用交互式控制台),但没有IDE或Eclipse/NetBeans插件.有什么建议 ?
曾经有人在SML中向我展示了一个小技巧,他们在他们的REPL中写出了大约3或4个函数,最后一个值的结果类型非常长(就像许多页面滚动一样长).
有谁知道什么代码生成这么长的类型,或者是否有这种行为的名称?
在Andrew Koenig的关于ML类型推理的轶事中,作者使用合并排序的实现作为ML的学习练习,并且很高兴地发现"不正确"的类型推断.
令我惊讶的是,编译器报告了一种类型
Run Code Online (Sandbox Code Playgroud)'a list -> int list
换句话说,这个sort函数接受任何类型的列表并返回一个整数列表.
那是不可能的.输出必须是输入的排列; 它怎么可能有不同的类型?读者肯定会发现我的第一个冲动:我想知道我是否在编译器中发现了一个错误!
在考虑了一些之后,我意识到还有另一种方法可以忽略它的论点:也许它根本没有返回.实际上,当我尝试它时,这正是发生的事情:
sort(nil)
确实返回nil
,但排序任何非空列表将进入无限递归循环.
当翻译成Haskell时
split [] = ([], [])
split [x] = ([x], [])
split (x:y:xs) = (x:s1, y:s2)
where (s1,s2) = split xs
merge xs [] = xs
merge [] ys = ys
merge xx@(x:xs) yy@(y:ys)
| x < y = x : merge xs yy
| otherwise = y : merge xx ys
mergesort [] = []
mergesort xs = merge …
Run Code Online (Sandbox Code Playgroud)