在向某人解释什么是类型类X时,我很难找到正好是X的数据结构的好例子.
所以,我请求示例:
我认为Monad到处都有很多例子,但Monad的一个很好的例子与之前的例子有一些关系可以完成图片.
我寻找彼此相似的示例,区别仅在于属于特定类型类的重要方面.
如果有人能够设法在这个层次结构的某个地方隐藏一个Arrow的例子(它是在Applicative和Monad之间吗?),那也会很棒!
多年来这个问题让我很困惑,考虑到这个网站的名字,这是值得一提的地方.
为什么我们程序员仍然有这个StackOverflow
问题?
为什么在每个主要语言中线程堆栈内存都必须在创建线程时静态分配?
我将在C#/ Java的上下文中发言,因为我最常使用它们,但这可能是一个更广泛的问题.
固定堆栈大小会导致巨大的问题:
现在,如果堆栈动态调整大小,上面的所有问题都会大大减轻,因为堆栈溢出只有在存在内存溢出时才有可能.
但事实并非如此.为什么?现代CPU有一些基本限制会使其变得不可能/效率低下吗?如果你考虑重新分配所带来的性能ArrayList
损失,它应该是可以接受的,因为人们一直使用结构而不会遭受太多痛苦.
所以,问题是,我错过了什么,StackOverflow不是问题,或者我错过了什么,有很多语言有动态堆栈,还是有一些很大的原因让这个不可能/难以实现?
编辑: 有人说性能会是个大问题,但请考虑一下:
我发现想要在我的功能程序中建模关系数据是很常见的.例如,在开发网站时,我可能希望使用以下数据结构来存储有关我的用户的信息:
data User = User
{ name :: String
, birthDate :: Date
}
Run Code Online (Sandbox Code Playgroud)
接下来,我想存储有关用户在我的网站上发布的消息的数据:
data Message = Message
{ user :: User
, timestamp :: Date
, content :: String
}
Run Code Online (Sandbox Code Playgroud)
此数据结构存在多个问题:
User
是脆弱的 - 您可能忘记更新User
数据结构中的所有事件.这些问题是可管理的,而我们的数据可以表示为树.例如,您可以像这样重构:
data User = User
{ name :: String
, birthDate :: Date
, messages :: [(String, Date)] -- you get the idea
}
Run Code Online (Sandbox Code Playgroud)
但是,可以将数据整形为DAG(想象任何多对多关系),甚至可以作为一般图形(好的,也许不是).在这种情况下,我倾向于通过在Map
s中存储我的数据来模拟关系数据库:
newtype Id a = Id Integer
type Table a = …
Run Code Online (Sandbox Code Playgroud) 我想更好地理解例如Data.Map的实习生.当我在Map中插入一个新的绑定时,由于数据的不变性,我得到一个与旧数据结构加上新绑定相同的新数据结构.
我想了解这是如何实现的.编译器最终是通过使用数百万个绑定复制整个数据结构来实现的吗?通常可以说可变数据结构/数组(例如Data.Judy)或命令式编程语言在这种情况下表现更好吗?在字典/键值存储方面,不可变数据是否具有任何优势?
教会编码(又名访客模式)是一种将数据表示为函数的方式:而不是
data T = C1 F1 F2 | C2 F3 F4
Run Code Online (Sandbox Code Playgroud)
你可以定义
data T = T (forall r. (F1 -> F2 -> r) -> (F3 -> F4 -> r) -> r)
Run Code Online (Sandbox Code Playgroud)
.虽然将任何东西表示为函数的能力很好,但我一直认为第一个版本更可取,因为它更清晰,并且不需要语言扩展(显式forall
).但是,您有时可以在公共图书馆中找到教会编码的数据.使用它有什么好处?
公共图书馆中教会编码的例子:
刚刚在Haskell的排序算法中弄湿了我的脚.我已经实现了insert-sort和merge-sort
insert_sort :: (Ord a, Show a) => [a] -> [a]
insert_sort keys = foldr f [] keys
where f key [] = [key]
f key acc = insert key acc
insert y [] = [y]
insert y (x:xs)
| x < y = x : insert y xs
| otherwise = y : x : xs
merge_sort :: (Ord a, Show a) => [a] -> [a]
merge_sort (x:[]) = [x]
merge_sort keys = merge (merge_sort (take len keys)) (merge_sort …
Run Code Online (Sandbox Code Playgroud) 考虑以下破坏的功能:
def sum (list : Seq[Int]) : Int = list match {
case Nil => 0
case head :: tail => head + sum(tail)
}
Run Code Online (Sandbox Code Playgroud)
在这里,该函数应该与a一起使用List[Int]
,但是被重构为接受Seq[Int]
,因此在没有编译器注意的情况下被破坏.
Scala不完整模式匹配检测中的这个空洞使得它几乎无用.
我想有办法系统地发现这些问题.具体来说,我希望编译器在每个instanceof
引导模式匹配时发出错误/警告,即我只想在密封层次结构和自定义匹配器上允许模式匹配.
是否存在用于对模式匹配安全性进行保守(而不是任意)检查的现有编译器选项/插件?
我试图将以下Haskell代码转换为C++:
data List t = Nil | Cons t (List t)
Run Code Online (Sandbox Code Playgroud)
将代数数据类型直接转换为无状态访问者模式会产生以下Java代码
interface List<T> {
<R> R accept(ListVisitor<T,R> v);
}
interface ListVisitor<T,R> {
R visitNil();
R visitCons(T head, List<T> tail);
}
class Nil<T> implements List<T> {
@Override
public <R> R accept(ListVisitor<T,R> v) {
return v.visitNil();
}
}
class Cons<T> implements List<T> {
public final T head;
public final List<T> tail;
public Cons(T head, List<T> tail) {
this.head = head;
this.tail = tail;
}
@Override
public <R> R accept(ListVisitor<T,R> v) { …
Run Code Online (Sandbox Code Playgroud) 当我偶然发现这种奇怪的行为时,我试图回答关于多态性与共享的另一个问题.
在GHCi中,当我明确定义一个多态常量时,它没有得到任何共享,这是可以理解的:
> let fib :: Num a => [a]; fib = 1 : 1 : zipWith (+) fib (tail fib)
> fib !! 30
1346269
(5.63 secs, 604992600 bytes)
Run Code Online (Sandbox Code Playgroud)
另一方面,如果我试图通过省略类型签名并禁用单态限制来实现相同的目标,那么我的常量会突然被分享!
> :set -XNoMonomorphismRestriction
> let fib = 1 : 1 : zipWith (+) fib (tail fib)
> :t fib
fib :: Num a => [a]
> fib !! 50
20365011074
(0.00 secs, 2110136 bytes)
Run Code Online (Sandbox Code Playgroud)
为什么?!
呃...当使用优化编译时,即使禁用单态限制也很快.