我一直在研究绳索作为Data.Text的替代品,我喜欢我所看到的以至于我现在不得不问这个问题....有没有哪种情况下Data.Text会是更好的选择?
以下是引导我的要点(如果我错在任何这些上,请纠正我) -
单个叶节点绳内部是(几乎)相同的东西作为一个Data.Text对象.单节点绳索与文本的开销很小,只是用于区分分支或叶子的单个位标志.如果你真的想要Data.Text,只需使用未分裂的绳索.
复杂性在绳索插入/删除(log(N)vs N)中普遍相等或更好,通过索引得到(log(N)/ N取决于树的深度对N).
我已经读过绳索的成功证明是c中的混合包,因为线程安全代码损害了性能.然而,这些问题在不可变的Haskell中无关紧要.事实上,在我看来,因此,Haskell和绳索是彼此的理想选择.
再次,就像我以前的类似问题一样,我对结构的抽象质量更感兴趣,而不是当前的情况(库使用,代码的强化程度等).如果你明天重写了Haskell库,你会用Data.Rope替换Data.Text吗?
我是monad变换器的长期用户,第一次使用monad变换器编写器....而且我觉得我做了一些不必要的事情.
我们正在开发一个具有多个数据库表的项目,并且将该集合硬编码到不同的monad堆栈变得笨重,所以我们决定将其分解为不同的可插入monad变换器,允许我们在功能类型级别进行选择,如下所示
doSomething::(HasUserTable m, HasProductTable m)=>Int->m String
Run Code Online (Sandbox Code Playgroud)
(HasXTable是类,XTableT是具体的monad变换器).这些独立的monad变压器可以完全模块化的方式插入或移除,并存储DB手柄,需要ResourceT等....
我的第一次尝试是将ReaderT包裹起来,它将用于保存数据库句柄.很明显,这是行不通的,因为ReaderT(和StateT等)不能在不使用硬编码"升力"链的情况下堆叠,从而破坏了堆叠元件的可插拔模块性.
唯一的解决方案似乎是编写完全独立的ReaderT monad副本,每个副本允许访问较低级别的其他副本.这是有效的,但解决方案充满了样板代码,就像这样
class HasUserTable m where
getUser::String->m User
newtype UserTableT m r = UserTableT{runUserTableT::String->m r}
--Standard monad instance stuff, biolerplate copy of ReaderT
instance Functor m=>Functor (UserTableT m) where....
instance Applicative m=>Applicative (UserTableT m) where....
instance Monad m=>Monad (UserTableT m) where....
instance Monad m=>HasUserTable (UserTableT m) where....
--Gotta hardcode passthrough rules to every other monad transformer
--in the world, mostly using "lift"....
instance MonadTrans BlockCacheT where....
instance (HasUserTable m, Monad m)=>HasUserTable …Run Code Online (Sandbox Code Playgroud) 内部的方式Data.Text和Data.Vector.Unboxed Char工作有什么不同吗?为什么我会选择一个而不是另一个?
我一直以为这是很酷的是哈斯克尔定义String为[Char].是否有一个原因的东西analagous对于没有这样做Text,并Vector Char?
使它们相同肯定会有一个优势......可以编写Text-y和Vector-y工具以在两个阵营中使用.想象一下Ints的绳索,或者扑克牌上的正则表达.
当然,我知道可能有历史原因,我理解大多数现有的图书馆使用的Data.Text不是Vector Char,所以有许多实际的理由支持一个而不是另一个.但是我更感兴趣的是了解抽象的品质,而不是我们碰巧在的当前状态......如果整个事情明天被重写,那么统一两者会更好吗?
编辑,更多信息 -
把东西放到透视图中 -
根据这个页面http://www.haskell.org/haskellwiki/GHC/Memory_Footprint,GHC为你的程序中的每个Char使用16个字节!
Data.Text不是O(1)索引,它是O(n).
Ropes(文本周围的二叉树)也可以包含字符串....它们具有更好的索引/插入/删除复杂性,尽管取决于节点的数量和树的平衡,索引可能接近于Text的索引.
这是我从这里得到的 -
Text和Vector Char是不同的内部....
如果您不关心性能,请使用String.
如果性能很重要,则默认使用Text.
如果需要快速索引字符,并且您不介意大量内存开销(最多16倍),请使用Vector Char.
如果要插入/删除大量数据,请使用Ropes.
GHC默默地忽略数值常量中的超出范围位.
这种行为导致我今天与一个相当奇怪的bug搏斗:
[0..256]::[Word8] -- evaluates to [0]!
Run Code Online (Sandbox Code Playgroud)
我知道是什么导致了这个错误(在rot256世界中256 == 0)....我感兴趣的是为什么GHC/Haskell的设计不会在编译时抱怨它.
(这种行为对于Int也是如此 - 例如,18446744073709551617::Int = 1).
我已经习惯了Haskell捕捉琐碎的编译时间问题,当我不得不追踪它时,我感到很惊讶.
我们需要在内存中存储大量1GB的连续字节很长一段时间(几周到几个月),并且正在尝试选择一个Vector/Array库.我有两个问题,我无法找到答案.
Vector.Unboxed似乎存储堆上的底层字节,可以由GC随意移动....定期移动1GB的数据将是我想要避免的.
Vector.Storable通过将基础字节存储在c堆中来解决此问题.但我读过的所有内容似乎都表明这只是用于与其他语言(主要是c)进行通信.是否有一些原因我应该避免使用Vector.Storable进行内部Haskell使用.
如果有意义,我愿意接受第三种选择!
使用esqueleto可以进行以下查询吗?
DELETE Table1
FROM Table1
INNER JOIN Table2 ON Table1.ID = Table2.ItemID
Run Code Online (Sandbox Code Playgroud)
我试过了:
delete $
from $ \(table1 `InnerJoin` table2) ->
on (table1 ^. Table1ID ==. table2 ^. Table2ItemID)
Run Code Online (Sandbox Code Playgroud)
奇怪的是,它产生了我在Haskell中见过的唯一运行时错误之一
ERROR: syntax error at or near "INNER"
LINE 2: FROM "table1" INNER JOIN "table2" ON "tab...
Run Code Online (Sandbox Code Playgroud)
(基本上,不幸的DELETE是错过了"table1")
我也尝试在monad中添加一个返回值,与select一样可能会添加该值.但这失败了,因为删除需要monad类型m ().
这可能是Esqueleto遗失的吗?
我正在寻找在索引i处插入/删除日志(N)的"列表".我把单词"List"放在引号中,因为我并不是说它是一个真正的Haskell List,而是任何带有一堆对象的有序容器(事实上,它可能需要内部的某种树).我很惊讶我还没有找到一个很好的解决方案....
这是我迄今为止最好的解决方案 - 使用Data.Sequence这两个函数.
doInsert position value seq = before >< ( value <| after)
where
(before, after) = splitAt position seq
doDelete position seq = before >< (drop 1 after)
where
(before, after) = splitAt position seq
Run Code Online (Sandbox Code Playgroud)
虽然这些在技术上都是log(N)函数,但感觉就像我为每个插入/删除做了一堆额外的东西....换句话说,这对于K更大的K来说就像K*log(N)一样比应该的.另外,由于我必须自己定义这些内容,我觉得我正在使用Sequence来实现它不适合的东西.
有没有更好的办法?
这是一个相关的问题(尽管它只涉及Sequences,我很乐意使用其他任何东西):为什么Data.Sequence没有`insert'或`insertBy',我该如何有效地实现它们?
是的,这个问题与我几天前发布的另一个问题有关:大量的XML编辑
如果我用GHC发出警告,它会警告我哪些进口没有被使用....
是否有类似的命令告诉我哪些文件build-depends没有被使用<project>.cabal?
这是一开始看起来容易的问题之一,但我已经研究了一段时间,但找不到答案....
我需要将字节列表(ie- Word8s)转换为任意长度的数字(即-a Integer).例如
intPack::[Word8]->Integer
intPack [1] = 1
intPack [1, 0] = 256
showHex (intPack [1,2,3,4,5,6,7,8,9,10,11]) "" = "102030405060708090a0b"
Run Code Online (Sandbox Code Playgroud)
一个缓慢的解决方案很容易编写(请参阅如何将ByteString转换为Int并处理字节序的答案 ?)
intPack = foldl (\v -> ((v*256) +)) 0
Run Code Online (Sandbox Code Playgroud)
....但是我对此畏缩,所有额外的乘法和加法,加上在中间创建的一串无用的整数,只是为了(可能)获得与打包到Integer类型的内部结构中相同的字节.
当然,我不知道Integer如何存储其数据的细节(也许它比在可变长度数组中保存字节更复杂......比如使用flags来表示数字的长度,比如utf -8在编码字符时执行).至少知道intPack上面的内容就像它一样好......然后我可以停止我的研究,咬一口(或者更确切地说是字节:)的子弹,继续前进.
我是堆栈的忠实粉丝,我已经从我的机器上完全删除了任何独立的cabal和ghc可执行文件(让堆栈在它自己神秘的〜/ .stack /目录中安装它需要的任何东西)....
但是,看起来有些标志在堆栈下无法正常工作.例如,我想使用-ddump-minimal-imports.在cabal这将是
cabal build --ghc-option=-ddump-minimal-imports
Run Code Online (Sandbox Code Playgroud)
明显的翻译是
stack build --ghc-options -ddump-minimal-imports
Run Code Online (Sandbox Code Playgroud)
这运行,但只生成可执行文件(据我所知,至少......也许输出是在神秘的〜/ .stack目录中的某个地方).
有没有办法做到这一点?