在ScopedTypeVariables扩展的GHC 文档中,概述将以下内容说明为设计原则:
范围类型变量代表类型变量,而不代表类型.(这是GHC早期设计的变化.)
我知道范围类型变量扩展的一般目的,但我不知道这里区分类型变量和代表类型之间的区别的含义.从语言用户的角度来看,差异的意义是什么?
上述评论暗示两种设计以不同方式处理此决策并做出不同的权衡.什么是替代设计,它与目前实施的设计相比如何?
令我惊讶的是,我发现在Haskell中舍入NaN值会返回一个巨大的负数:
round (0/0)
-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824
Run Code Online (Sandbox Code Playgroud)
地板和天花板也是如此.
这里发生了什么?这种行为是有意的吗?当然,我理解任何不想要这种行为的人总是可以编写另一个检查isNaN的函数 - 但是现有的替代标准库函数是否能够更加理智地处理NaN(对于"更理智"的某些定义)?
我有f类型的功能Integral => a -> a -> Maybe a.这意味着
f 1 2
Run Code Online (Sandbox Code Playgroud)
是有效的代码,但自然的组成
f (f 3 4) 5
f 6 (f 7 8)
f (f 9 10) (f 11 12)
Run Code Online (Sandbox Code Playgroud)
无效.
有办法让它发挥作用.例如,
f 6 =<< f 7 8
Run Code Online (Sandbox Code Playgroud)
对于案例2,我知道的最好的方式.对于案例3,
join $ f <$> f 9 10 <*> f 11 12
Run Code Online (Sandbox Code Playgroud)
是我能想到的最好的,但额外的join伸出像拇指疼痛.我对案例1没有好主意.除此之外,令我困扰的是我提出的语法并不"一致" - 我基本上完成了同样的事情,但语法却非常不同.
是否有一个标准的/惯用的建设,让我转换f工作的Maybe a -> a -> Maybe a,a -> Maybe a -> Maybe a以及Maybe a -> …
任意精度有符号整数几乎总是使用符号数值表示来实现:
对符号数值的明显偏好与固定宽度有符号整数类型中对二进制补码的近乎普遍的偏好形成鲜明对比。问题是,为什么符号数值对于 BigIntegers 来说如此明显是首选?(如果您不同意前提,我欢迎反例。)
请注意,BigInteger API 通常为重要的位运算指定“如同二进制补码”语义(例如Java、Python )。这提供了与这些操作的通常含义的一致性。这并不规定实际的内部表示(仅是实现细节),但如果其他条件相同,它应该是支持在内部使用二进制补码的一点。
浮点数使用符号数值,与使用二进制补码的整数不同。不过,浮点并不是真正的指导先例,因为浮点运算的行为和算法与整数运算有很大不同。Bignum 更像整数而不是浮点数。
我们知道“教科书”上为什么补码在数学上起作用以及为什么它有优点的原因。在我看来,这些原因同样适用于整数和大整数。这在多大程度上是真的?
当然,硬件固定精度整数和软件任意精度整数的设计约束之间存在巨大差异。从这个意义上说,看到设计师在这些不同的领域做出不同的权衡一点也不奇怪。那么,应用于任意精度整数时,符号-数值和补码之间的权衡是什么?例如,这可能涉及某些重要算法的性能或简单性。
我希望您的回答能够阐明 BigInteger 算术的设计注意事项,并帮助我从新的角度重新审视我对补码的了解。
(需要明确的是:当我说任意精度整数的二进制补码时,我的意思是使用单词数组的表示,其位模式放在一起时是所需数字的二进制补码表示 - 也许还有额外的要求没有“不必要的前导 0”(对于非负数)或“不必要的前导 1”(对于负数)。)
考虑一个模式中引入的变量,例如f在这个Haskell示例中:
case (\x -> x) of f -> (f True, f 'c')
Run Code Online (Sandbox Code Playgroud)
此代码导致类型错误("无法将预期类型'Bool'与实际类型'Char'匹配"),因为它有两种不同的用途f.它表明推断类型f在Haskell中不是多态的.
但为什么不应该f是多态的?
我有两点比较:OCaml和"教科书"Hindley-Milner.两者都表明f应该是多态的.
在OCaml中,类似的代码不是错误:
match (fun x -> x) with f -> (f true, f 'c')
Run Code Online (Sandbox Code Playgroud)
这将(true, 'c')使用类型进行评估bool * char.所以看起来OCaml与指定f多态类型相处得很好.
我们可以通过使用"let"来解决Hindley-Milner - lambda演算的基本原理来获得清晰度 - Haskell和OCaml都是基于它的.当减少到这个核心系统时,当然没有模式匹配这样的东西.我们可以画出相似之处.与"让"和"拉姆达",case expr1 of f -> expr2是更接近let f = expr1 in expr2比(lambda f. expr2) expr1."case",就像"let"一样,在语法上限制f绑定expr1,而一个函数lambda f. expr2不知道 …
我正在使用bash,据我所知,exec后跟一个命令应该替换shell而不创建新进程.例如,
exec echo hello
Run Code Online (Sandbox Code Playgroud)
具有打印"hello"然后立即退出的外观,因为在完成echo之后,shell进程不再返回.
如果我把它作为管道的一部分 - 例如,
exec echo hello | sed 's/hell/heck/'
Run Code Online (Sandbox Code Playgroud)
要么
echo hello | exec sed 's/hell/heck/'
Run Code Online (Sandbox Code Playgroud)
我的期望是,同样地,shell会因为其进程被替换而终止.这不是现实中发生的事情 - 上面的命令都打印"hecko"并正常返回shell,就好像"exec"这个词不存在一样.为什么是这样?