我很困惑如何在data family和之间做出选择type family.TypeFamilies上的维基页面详细介绍了很多.偶尔它会非正式地将Haskell data family称为散文中的"类型家族",但当然也存在type family于Haskell中.
有一个简单的例子显示了两个版本的代码的显示位置,区别仅在于a data family或a type family是否被声明:
-- BAD: f is too ambiguous, due to non-injectivity
-- type family F a
-- OK
data family F a
f :: F a -> F a
f = undefined
g :: F Int -> F Int
g x = f x
Run Code Online (Sandbox Code Playgroud)
type与data此具有相同的含义,但type family版本没有类型检查,而data family版本是好的,因为data family"创造了新的类型,因此射"(说的wiki页面).
我从这一切中得到的结论是"尝试data family …
手指树(Data.Sequence)和绳子(Data.Rope)之间的主要区别是什么(Edward Kmett的版本或Pierre-Etienne Meunier的版本?
在Haskell库中,Data.Sequence具有更多功能.我认为绳索可以更有效地处理"块".
作为程序员考虑效率处理,比如一个700万个字符的序列,我需要做的事情(a)插入任何地方,(b)剪切和粘贴段(拼接),(c)搜索和替换子串,这是更高效?
澄清回应ehird:
我的大部分算法都在运行数千个搜索替换操作,比如s/(ome)?reg[3]x/blah$1/g重复改变数据.所以,我需要有效的正则表达式模式匹配(可能形成的正则表达式-TDFA?)以及剪接(数据[A:B] = newData),其中,不一定(length(newData) == b-a+1)
懒惰的ByteStrings可能没关系,但是拼接怎么样?拼接ByteString是O(dataSize/chunkSize)线性时间(用于搜索),加上(可能是?)开销用于维护恒定大小的块.(后一部分可能是错的); 对于FingerTree,vs O(log(dataSize)).
我的"容器"数据类型抽象地是有限字母表.它可以具体地表示为Chars或Bytes或Word8s或甚至类似于假设的Word4s(半字节).**我有一个相关的问题,关于如何有效地使用一个newtype或data多个我的代码可以引用抽象字母表,但编译的程序仍然可以是有效的.(我应该单独发布这个问题.)
性能问题:也许Seq远比ByteString差(通过q显着的常数因子).在简单的测试中,将7MB读入严格ByteString,然后将其打印到60MB真实内存使用的控制台峰值(根据Windows Process Manager),但将该内容加载到a Seq Char然后打印使用400MB!(我应该单独发布这个问题,包括代码和分析详细信息.)
平台问题:我正在使用EclipseFP和Haskell平台.我在我的机器上安装了Text,我想尝试一下,但我的Eclipse环境找不到它.我得到了很大的麻烦,每当我用cabal install(包的不兼容版本得到安装,--userVS --global混乱),所以我要坚持用平台软件包EclipseFP可以找到.我认为Text将进入下一版本的平台,所以这将很好.
Trifecta:我简单地看到了Trifecta,这加剧了我的困惑.(为什么它有自己的已经发布的一般数据结构的新实现?它们更好吗?太多几乎相同的选项!)
编辑了更多细节和改进的链接.
@ ehird的总结是主要的回归点.绳索,或ByteStrings或矢量的手指树加上一个小的自定义幺半群.无论哪种方式,我都必须编写一个简单的正则表达式实现来粘合.
鉴于所有这些信息,我建议使用Rope,或使用它所基于的fingertree包构建自己的结构(而不是Seq,以便您可以使用Measured类类正确实现长度 - 请参阅Monoids和Finger Trees) ,将叶数据分块为未装箱的Vector.当然,后者是更多的工作,但让你专门针对你的用例进行优化.无论哪种方式,绝对将它包装在一个抽象的界面中.
我今天晚些时候会回来并分成新的问题.我将整理出低级技术问题,然后再回到整体比较中.我将更改问题标题以更好地反映我真正关心的问题"哪些Haskell模块提供或支持我需要的序列操作操作?" …
在Haskell中,是否有用于生成Random/ Arbitrary枚举的"标准"库/包?
我写了下面的代码,但我不敢相信我是第一个有这个需求或解决它的人(而且我不确定我的解决方案是完全正确的).此外,我希望现有的解决方案还有其他不错的功能.
这是一对从Enum类型中选择随机值的函数:
enumRandomR :: (RandomGen g, Enum e) => (e, e) -> g -> (e, g)
enumRandomR (lo,hi) gen =
let (int, gen') = randomR (fromEnum lo, fromEnum hi) gen in (toEnum int, gen')
enumRandom :: (RandomGen g, Enum e) => g -> (e, g)
enumRandom gen =
let (int, gen') = random gen in (toEnum int, gen')
Run Code Online (Sandbox Code Playgroud)
这里是实例System.Random.Random和Test.QuickCheck.Arbitrary
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
instance (Enum a, Bounded a) => …Run Code Online (Sandbox Code Playgroud) 我很懒,写了一个Haskell模块(使用优秀的EclipseFP IDE)而没有给我的顶级函数提供类型签名.
EclipseFP使用HLint自动标记每个违规函数,我可以通过4次鼠标点击来修复每个函数.有效,但乏味.
是否有一个实用程序将扫描.hs文件,并发出一个修改版本,为每个顶级函数添加类型签名?
例:
./addTypeSignatures Foo.hs
Run Code Online (Sandbox Code Playgroud)
会读取一个文件Foo.hs:
foo x = foo + a
Run Code Online (Sandbox Code Playgroud)
并发出
foo :: Num a => a -> a
foo x = x + 1
Run Code Online (Sandbox Code Playgroud)
如果工具自动编辑Foo.hs并保存备份,则奖励积分Foo.bak.hs
我有一个可执行文件的核心转储,它不是用调试符号构建的.
我可以恢复argv内容以查看命令行是什么吗?
如果我运行gdb,我可以看到一个回溯,我可以导航到main()框架.在那里,有没有办法恢复argv,而不知道它的确切地址?
我在运行CEntOS Linux发行版/内核的x86_x64(Intel Xeon CPU)上,
我希望的一个原因是核心转储似乎显示部分argv.
(该程序是postgres,当我加载核心文件时,gdb打印一条消息,其中包含postgres db-user名称,客户端OP地址和查询的前10个字符))
其中一个受到高度关注的特性是,如果一个程序编译,它很可能大部分是正确的,比用不太复杂或严格类型系统的语言编写的程序更为正确.
也就是说,Haskell是一个将运行时错误转换为编译器错误的系统:-)
我想知道,Haskell中的编程是否会导致程序员在一种不太强类型的语言中引入一个运行时错误,而该错误没有明显的模拟(外观和频率)?
一些基本的例子突然出现在我脑海中:(不是很好,我正在寻找关于警惕的建议)
其他/更好的陷阱的例子?
在Haskell中,类型构造函数当然可以采用类型参数.
a -> b当一个函数被视为"具有有趣构造函数名称的类型"时,它具有类型(->) a b.这使它成为一个(->)带有两个参数的类型构造函数,a并且b.这在"读者"模式中经常遇到,如在其Functor和Applicative实例中:
instance Functor ((->) a) where
fmap = (.)
instance Applicative ((->) a) where
pure = const
(<*>) f g x = f x (g x)
Run Code Online (Sandbox Code Playgroud)
当我第一次尝试理解这个实例的用法时,如
fmap (+1) (*2) 3(=== (+1) . (*2) $ 3=== 3*2+1=== 7)
我的反应是"好了,(+1)已经输入Int -> Int,也就是(->) Int Int,使匹配Functor....但哪里是Int?我做一个Maybe Int调用 …
我想阅读一个库的源代码(例子),但是Haddock的注释很漂亮(例子).http://www.haskell.org/ghc/docs有这两种观点,但没有将它们组合在一起.
有没有人制作用户界面来一起查看这些内容?它基本上是渲染视图,但每个函数/类的源代码/在每个渲染的doc项目下面直接插入的内容.
我有一个看起来像这样的类型:
newtype Canonical Int = Canonical Int
Run Code Online (Sandbox Code Playgroud)
和一个功能
canonicalize :: Int -> Canonical Int
canonicalize = Canonical . (`mod` 10) -- or whatever
Run Code Online (Sandbox Code Playgroud)
(Canonical类型可能并不重要,它只是用于区分"原始"值和"规范化"值.)
我想创建一些机器,以便我可以规范化函数应用程序的结果.
例如:( 编辑:固定的虚假定义)
cmap :: (b->Int) -> (Canonical b) -> (Canonical Int)
cmap f (Canonical x) = canonicalize $ f x
cmap2 :: (b->c->Int) -> (Canonical b) -> (Canonical c) -> (Canonical Int)
cmap2 f (Canonical x) (Canonical y) = canonicalize $ f x y
Run Code Online (Sandbox Code Playgroud)
这表面上与Functor和Applicative类似,但它并不完全,因为它太专业了:我实际上不能编写函数(按照Functor/Applicative的同态定律的要求),除非'b'是Int.
我的目标是利用现有的,而不是写我自己的变种一样的库函数/组合程序,cmap,cmap2.那可能吗?是否有不同的类型类或构造Canonical类型的不同方式来实现我的目标?
我尝试过其他结构,比如
newtype Canonical a = …Run Code Online (Sandbox Code Playgroud)