在经过几年乱丢乱的图书馆之后,我开始提出这个问题并提出这样的定义:
fragileZip :: [t1] -> [t2] -> [(t1, t2)]
fragileZip a b = loop a b
where
loop [] [] = []
loop (h1:t1) (h2:t2) = (h1,h2) : loop t1 t2
loop _ _ = error "fragileZip: lists were not the same length."
我的经验是,在Haskell前奏中做出的决定 - 关于take
,drop
,zip
等不会因为元素不足而错误 - 允许使用无限列表的可爱技巧,并且在某些情况下可能很方便,但是,例如,当预计长度相同的压缩列表时,它们是静默失败的狡猾来源。
是否有人知道一个完整的Data.List
替换,试图成为"脆弱的"像上面的zip一样,如果不满足期望,总是会抛出错误:如果列表长度不匹配,或者元素不足?
[脚注:是的,用总功能编程是好的,但这意味着用类型级信息释放相关证明义务,而不是通过返回错误值来掩盖错误!标准zip悄然丢失数据可能就是这样一种无声的失败。另外,我并不关心如何传达错误结果(例外,可能或者是其中之一)。如果现有的hackage lib适合账单,我会采取任何措施!]
答案 0 :(得分:4)
safe
包中包含来自Prelude
的许多函数的“更安全”版本;它们不会抛出错误,而是在失败时返回Maybe
值。但是,您仍将在运行时检测错误。
errors
包重新导出safe
中的函数,并添加其他便利函数以进行错误处理。
如果您愿意深入研究Haskell的新的依赖类型功能,sized-vector
包提供了在编译时检查其大小的列表。特别是,zipSame
函数只能压缩具有相同长度的列表:
{-# LANGUAGE DataKinds #-}
import Data.Vector.Sized
import Data.Type.Natural
vec2 :: Vector Char Two
vec2 = 'a' :- 'b' :- Nil
vec3 :: Vector Char Three
vec3 = 'x' :- 'y' :- 'z' :- Nil
vecZipped = zipSame vec2 vec3
此代码在编译时失败,错误为:
Couldn't match type 'S Zero with 'Z
Expected type: Vector Char Two
Actual type: Vector Char Three
In the second argument of `zipSame', namely `vec3'
In the expression: zipSame vec2 vec3
In an equation for `vecZipped': vecZipped = zipSame vec2 vec3
有关sized-vector
和Haskell上的依赖类型的教程,请参阅here。 comments也有有用的信息。
(有时候,你想要的是不同大小的压缩列表。我经常将有限列表压缩为无限列表,因为后者更容易定义。)
答案 1 :(得分:3)
我认为你提出的问题违背了Haskell的哲学。涉及error
或任何其他运行时崩溃的代码由于正当理由而不好。
但很明显,如果你愿意,可以自己创建一个包装器:
fragileZip :: [a] -> [b] -> [(a,b)]
fragileZip x y = if length x == length y
then zip x y
else error "Not of the same length"
如果您确实想在结果类型中展示一些错误,请使用类型Maybe
或Either
。例如:
fragileZip :: [a] -> [b] -> Maybe [(a,b)]
fragileZip x y = if length x == length y
then Just $ zip x y
else Nothing
答案 2 :(得分:1)
您的zip可以在list-extras包中找到pair
。还有safe个包,虽然它会解决head
,tail
及其错误的错误,而不是zip
,drop
等。