我试图通过一个实现点积的简单例子来获得类型级自然数的悬念.我代表这样的点积:
data DotP (n::Nat) = DotP [Int]
deriving Show
Run Code Online (Sandbox Code Playgroud)
现在,我可以mappend为点积的每个单独大小创建一个monoid实例(实际的点积),如下所示:
instance Monoid (DotP 0) where
mempty = DotP $ replicate 0 0
mappend (DotP xs) (DotP ys) = DotP $ zipWith (*) xs ys
instance Monoid (DotP 1) where
mempty = DotP $ replicate 1 0
mappend (DotP xs) (DotP ys) = DotP $ zipWith (*) xs ys
instance Monoid (DotP 2) where
mempty = DotP $ replicate 2 0
mappend (DotP xs) (DotP ys) = DotP $ …Run Code Online (Sandbox Code Playgroud) 在GHCI中,我运行这个简单的测试:
encodeFile "test" [0..10000000]
Run Code Online (Sandbox Code Playgroud)
该线路运行速度非常快(<10秒),但我的内存使用量在完成之前会达到~500MB.不应该编码文件是懒惰的,因为它使用ByteString.Lazy?
编辑:罗曼的答案很棒!我还想指出另一个问题的答案,这解释了为什么Data.Binary对列表进行严格编码并提供稍微优雅的解决方法.
我懒惰地使用这段代码编码列表(取自这个SO问题):
import Data.Binary
newtype Stream a = Stream { unstream :: [a] }
instance Binary a => Binary (Stream a) where
put (Stream []) = putWord8 0
put (Stream (x:xs)) = putWord8 1 >> put x >> put (Stream xs)
Run Code Online (Sandbox Code Playgroud)
问题是解码实现不是懒惰的:
get = do
t <- getWord8
case t of
0 -> return (Stream [])
1 -> do x <- get
Stream xs <- get
return (Stream (x:xs))
Run Code Online (Sandbox Code Playgroud)
这看起来像我应该是懒惰的,但是如果我们运行这个测试代码:
head $ unstream (decode $ encode $ Stream [1..10000000::Integer] …Run Code Online (Sandbox Code Playgroud) 我正在使用QuickCheck来测试我的代码以进行一些数值计算.基本上我有一个确切的功能和几个近似的效率更高.
我目前正在实现我想要测试的属性:
prop_blah input = (abs $ (exact input)-(approx input)) < threshold
Run Code Online (Sandbox Code Playgroud)
但是,确切地知道每种近似算法的准确度并将它们相互比较真的很不错.一种简单的方法是获得不等式左侧的均值和标准差的报告.这有点可能吗?
我可能会画一个单词列表,如:
this -> is -> a -> test
Run Code Online (Sandbox Code Playgroud)
然后通过分享,我可以绘制两个列表:
this -> is -> a -> test
^
|
that -> was -> a -> hard
Run Code Online (Sandbox Code Playgroud)
现在,如果我反转箭头,我得到一棵树,以测试为根.这与图/类别理论中的二元性概念相同.因此,我可以将树木和列表视为双重概念.
这是正确/有用的吗?
给定一个功能
f :: Vector a => a -> b
Run Code Online (Sandbox Code Playgroud)
我们会调用a一个类型(或类型变量)和Vector一个约束.但是我们称之为满足所有类型的集合Vector a => a呢?我一直在非正式地称它为"矢量空间集",我将任何成员类型称为"向量空间".我应该使用更准确的类型理论名称吗?特别是,"set"和"space"这两个词是否正确使用?
对于我的项目,我已经将一些单元测试写成了bash脚本.确实没有合理的方法在Haskell中编写测试.
我想在输入时运行这些脚本cabal test.我该如何做到这一点?
让我用一个例子解释一下成本敏感折叠的含义:用任意精度计算pi.我们可以使用Leibniz公式(效率不高,但又好又简单)和懒惰的列表如下:
pi = foldr1 (+) [(fromIntegral $ 4*(-1)^i)/(fromIntegral $ 2*i+1) | i<-[0..]]
Run Code Online (Sandbox Code Playgroud)
现在,显然这个计算永远不会完成,因为我们必须计算无限列表中的每个值.但实际上,我不需要pi的确切值,我只需要它到指定的小数位数.我可以像这样定义pi':
pi' n = foldr1 (+) [(fromIntegral $ 4*(-1)^i)/(fromIntegral $ 2*i+1) | i<-[0..n]]
Run Code Online (Sandbox Code Playgroud)
但是,根本不清楚我需要传递什么值以获得我想要的精度.我需要的是某种对成本敏感的折叠,只要达到所需的精度就会停止折叠.这样的折叠存在吗?
(注意,在这种情况下,很容易看出我们是否已达到所需的精度.因为Leibniz公式使用了一个与每个术语交替出现符号的序列,所以误差总是小于下一个术语的绝对值.序列.)
编辑:拥有对成本敏感的折叠也很酷,这也可以考虑计算时间/功耗.例如,我想要最准确的pi值,因为我有1小时的计算时间和10kW小时的花费.但我意识到这将不再具有严格的功能.
只是为了好玩,我想创建一个类型级列表,知道它有多长.像这样的东西:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import GHC.TypeLits
data family TypeList a (n::Nat)
data instance TypeList a (0) = EmptyList
data instance TypeList a (1) = TL1 a (TypeList a (0))
data instance TypeList a (2) = TL2 a (TypeList a (1))
data instance TypeList a (3) = TL3 a (TypeList a (2))
Run Code Online (Sandbox Code Playgroud)
但是,我当然希望将其概括为:
data instance TypeList a (n) = TL3 a (TypeList a (n-1))
Run Code Online (Sandbox Code Playgroud)
但这会产生错误:
TypeList.hs:15:53: parse error on input `-'
Failed, …Run Code Online (Sandbox Code Playgroud) 我想在我的Haskell项目中使用travis-ci,但它们需要最新版本的GHC.
我有一个表单的数据类型:
data T = { a :: Int, b :: ComplexOtherDataType }
Run Code Online (Sandbox Code Playgroud)
我显然可以将这些放入Data.Vector模块的常规向量中.但是当我访问a组件时,我想要非常,非常好的性能,因此额外的间接是不可取的.我想做的是做T一个实例Data.Vector.Unboxed.Unbox,但仍然b是懒惰的.
在vector-th-unbox提供了用于制备的实例的漂亮的模板哈斯克尔接口Unbox,但它不会在我的情况下工作.它要求,为了使T实例Unbox,都a 和 b也必须实例.但我不想拆箱b.我希望它是盒装/懒惰的.
我的直觉说,克服这个障碍的最简单方法是提供一种类型
newtype LazyUnbox a = LazyUnbox a
Run Code Online (Sandbox Code Playgroud)
然后,我需要提供一个Unbox实例LazyUnbox,基本上只是将指针存储在未装箱的矢量中.我怎样才能做到这一点?还是完全有更好的方法?
我有一个包含大约 1 亿行的表格和一个我想搜索的文本字段。我想出了两种方法来做到这一点,我想知道每种方法的性能影响。
方法 1: 这是我在网上看到的每篇博文都推荐的方法(例如1和2 .)。这个想法是用一ts_vector列扩充表并索引新列。
一个简单的例子是:
CREATE TABLE articles (
id_articles BIGSERIAL PRIMARY KEY,
text TEXT,
text_tsv TSVECTOR
);
CREATE INDEX articles_index ON articles USING gin(text_tsv);
Run Code Online (Sandbox Code Playgroud)
然后使用触发器来确保text和text_tsv列保持最新。
然而,这对我来说似乎很浪费,因为现在TSVECTOR信息必须同时存储在表和索引中,并且数据库变得更加复杂。所以我想出了第二种方法。
方法二:
我的想法是去掉多余的列,改索引to_tsvector直接包含函数,像这样:
CREATE TABLE articles (
id_articles BIGSERIAL PRIMARY KEY,
text TEXT
);
CREATE INDEX articles_index ON articles USING gin(to_tsvector(text));
Run Code Online (Sandbox Code Playgroud)
问题:与方法 1 相比,使用方法 2 有什么缺点吗?
对于我的特定数据库,我使用了第二种方法,对于单个单词的简单查询,我似乎获得了合理的加速(搜索需要大约 1 秒)。但是,当我在函数中使用多个&和|运算符进行复杂查询to_tsquery(并且表中只有大约 10 个匹配结果)时,搜索需要永远运行(许多小时)。如果我切换到方法 …
当我看到这个非常有趣的例子时,我正在浏览关于TypeNats的GHC维基部分.他们正在创建类型列表:
type family Get (n :: Nat1) (xs :: [*]) :: *
type instance Get Zero (x `: xs) = x
type instance Get (Succ n) (x `: xs) = Get n xs
Run Code Online (Sandbox Code Playgroud)
我想了解更多相关信息.我假设这个功能没有在7.6.1中实现(至少它不能为我编译),并且浏览门票证明是非常压倒性的.知道我应该寻找什么吗?
haskell ×12
types ×3
cabal ×1
definition ×1
fold ×1
ghc ×1
list ×1
postgresql ×1
quickcheck ×1
terminology ×1
travis-ci ×1
tree ×1
tsvector ×1
vector ×1