Haskell 元组列表与元组比较
Haskell list of tuples vs tuple comparrison
我正在尝试 Haskell 中的第一个不平凡的(在我看来)尝试。我可能会问关于每个部分的问题,以比较我与 C 类语言建立长期关系的尝试与您作为经验丰富的函数式程序员可能会做的事情。幸运的是,Haskell 很难退回到直接的 c 到 haskell 代码转换。你必须学习如何正确地做事 - 我想。
对于这部分,我有一个 [2uple] 和一个 2uple。我想知道 2uple 中的任何项目是否在 [2uple] 中的任何项目中。
hasmatch tlst tupm = foldr (\tup acc ->
let tmatch (a,b) (c,d) = a==c || b==c || a==d || b==d in
if tmatch tup tupm
then (Just True) -- short out
else acc -- do nothing, keep looping
) Nothing tlst
-- hasmatch [(1,2), (3,4), (5,6)] (5,3) ==> Just True
-- hasmatch [(1,2), (9,4), (7,6)] (5,3) ==> Nothing
我更喜欢 return 一个普通的 Bool,但没什么大不了的。
我敢肯定还有另一种方法我需要花上一段时间才能理解。那很好。正在寻找接受者。
谢谢
让我们从您的代码开始。
hasmatch tlst tupm =
foldr (\tup acc ->
let tmatch (a,b) (c,d) = a==c || b==c || a==d || b==d in
if tmatch tup tupm
then (Just True) -- short out
else acc -- do nothing, keep looping
) Nothing tlst
既然你说你更喜欢布尔结果,我们可以切换到那个。事实上,布尔值会更好,因为在上面的代码中我们从来没有 return Just False
.
hasmatch tlst tupm =
foldr (\tup acc ->
let tmatch (a,b) (c,d) = a==c || b==c || a==d || b==d in
if tmatch tup tupm
then True -- short out
else acc -- do nothing, keep looping
) False tlst
现在,if x then True else y
就是 x || y
。
hasmatch tlst tupm =
foldr (\tup acc ->
let tmatch (a,b) (c,d) = a==c || b==c || a==d || b==d in
tmatch tup tupm || acc
) False tlst
如果您想知道,当我们找到匹配项时,||
不会计算 acc
。这是与 C 短路相同的惰性语义。与 C 相比,主要区别在于布尔变量 acc
可以表示 未计算的 布尔结果,而在 C 中它始终是完全计算的布尔值。
现在,tmatch
使用相同的第二个参数,tupm
,所以我们可以内联它,并尽早进行模式匹配:
hasmatch tlst (c,d) =
foldr (\tup acc ->
let tmatch (a,b) = a==c || b==c || a==d || b==d in
tmatch tup || acc
) False tlst
我们甚至可以将 let
移到外面以提高可读性。
hasmatch tlst (c,d) =
let tmatch (a,b) = a==c || b==c || a==d || b==d
in foldr (\tup acc -> tmatch tup || acc) False tlst
我们也可以在这里使用where
:
hasmatch tlst (c,d) = foldr (\tup acc -> tmatch tup || acc) False tlst
where tmatch (a,b) = a==c || b==c || a==d || b==d
最后,我们可以利用一个库函数:any
。调用 any p list
计算结果为 True
当且仅当 list
中有任何元素满足 属性 p
。我们的代码变为:
hasmatch tlst (c,d) = any tmatch tlst
where tmatch (a,b) = a==c || b==c || a==d || b==d
就是这样。
请注意,上述方法还有其他替代方法。可以将元组列表 [(a,b), (c,d), ...
转换为所有组件的列表 [a,b,c,d,...
,然后使用它。
hasmatch tlst (c,d) = any tmatch [ x | (a,b) <- tlst, x <- [a,b]]
where tmatch x = x==c || x==d
根据 chi 的回答,您最好定义具有这种相等性的数据类型?
{-# Language DerivingStrategies #-}
{-# Language InstanceSigs #-}
{-# Language StandaloneKindSignatures #-}
import Data.Kind (Type)
type AnyTuple :: Type -> Type
data AnyTuple a = a :×: a
deriving stock Show
instance Eq a => Eq (AnyTuple a) where
(==) :: AnyTuple a -> AnyTuple a -> Bool
a1:×:b1 == a2:×:b2 = or $ liftA2 (==) [a1, b1] [a2, b2]
那么你要找的函数就是一个标准的库函数,比如elem
or find
>> 5:×:3 `elem` [1:×:2, 3:×:4, 5:×:6]
True
>> 5:×:3 `elem` [1:×:2, 9:×:4, 7:×:6]
False
>> find (== 5:×:3) [1:×:2, 3:×:4, 5:×:6]
Just (3 :×: 4)
>> find (== 5:×:3) [1:×:2, 9:×:4, 7:×:6]
Nothing
我正在尝试 Haskell 中的第一个不平凡的(在我看来)尝试。我可能会问关于每个部分的问题,以比较我与 C 类语言建立长期关系的尝试与您作为经验丰富的函数式程序员可能会做的事情。幸运的是,Haskell 很难退回到直接的 c 到 haskell 代码转换。你必须学习如何正确地做事 - 我想。
对于这部分,我有一个 [2uple] 和一个 2uple。我想知道 2uple 中的任何项目是否在 [2uple] 中的任何项目中。
hasmatch tlst tupm = foldr (\tup acc ->
let tmatch (a,b) (c,d) = a==c || b==c || a==d || b==d in
if tmatch tup tupm
then (Just True) -- short out
else acc -- do nothing, keep looping
) Nothing tlst
-- hasmatch [(1,2), (3,4), (5,6)] (5,3) ==> Just True
-- hasmatch [(1,2), (9,4), (7,6)] (5,3) ==> Nothing
我更喜欢 return 一个普通的 Bool,但没什么大不了的。
我敢肯定还有另一种方法我需要花上一段时间才能理解。那很好。正在寻找接受者。
谢谢
让我们从您的代码开始。
hasmatch tlst tupm =
foldr (\tup acc ->
let tmatch (a,b) (c,d) = a==c || b==c || a==d || b==d in
if tmatch tup tupm
then (Just True) -- short out
else acc -- do nothing, keep looping
) Nothing tlst
既然你说你更喜欢布尔结果,我们可以切换到那个。事实上,布尔值会更好,因为在上面的代码中我们从来没有 return Just False
.
hasmatch tlst tupm =
foldr (\tup acc ->
let tmatch (a,b) (c,d) = a==c || b==c || a==d || b==d in
if tmatch tup tupm
then True -- short out
else acc -- do nothing, keep looping
) False tlst
现在,if x then True else y
就是 x || y
。
hasmatch tlst tupm =
foldr (\tup acc ->
let tmatch (a,b) (c,d) = a==c || b==c || a==d || b==d in
tmatch tup tupm || acc
) False tlst
如果您想知道,当我们找到匹配项时,||
不会计算 acc
。这是与 C 短路相同的惰性语义。与 C 相比,主要区别在于布尔变量 acc
可以表示 未计算的 布尔结果,而在 C 中它始终是完全计算的布尔值。
现在,tmatch
使用相同的第二个参数,tupm
,所以我们可以内联它,并尽早进行模式匹配:
hasmatch tlst (c,d) =
foldr (\tup acc ->
let tmatch (a,b) = a==c || b==c || a==d || b==d in
tmatch tup || acc
) False tlst
我们甚至可以将 let
移到外面以提高可读性。
hasmatch tlst (c,d) =
let tmatch (a,b) = a==c || b==c || a==d || b==d
in foldr (\tup acc -> tmatch tup || acc) False tlst
我们也可以在这里使用where
:
hasmatch tlst (c,d) = foldr (\tup acc -> tmatch tup || acc) False tlst
where tmatch (a,b) = a==c || b==c || a==d || b==d
最后,我们可以利用一个库函数:any
。调用 any p list
计算结果为 True
当且仅当 list
中有任何元素满足 属性 p
。我们的代码变为:
hasmatch tlst (c,d) = any tmatch tlst
where tmatch (a,b) = a==c || b==c || a==d || b==d
就是这样。
请注意,上述方法还有其他替代方法。可以将元组列表 [(a,b), (c,d), ...
转换为所有组件的列表 [a,b,c,d,...
,然后使用它。
hasmatch tlst (c,d) = any tmatch [ x | (a,b) <- tlst, x <- [a,b]]
where tmatch x = x==c || x==d
根据 chi 的回答,您最好定义具有这种相等性的数据类型?
{-# Language DerivingStrategies #-}
{-# Language InstanceSigs #-}
{-# Language StandaloneKindSignatures #-}
import Data.Kind (Type)
type AnyTuple :: Type -> Type
data AnyTuple a = a :×: a
deriving stock Show
instance Eq a => Eq (AnyTuple a) where
(==) :: AnyTuple a -> AnyTuple a -> Bool
a1:×:b1 == a2:×:b2 = or $ liftA2 (==) [a1, b1] [a2, b2]
那么你要找的函数就是一个标准的库函数,比如elem
or find
>> 5:×:3 `elem` [1:×:2, 3:×:4, 5:×:6]
True
>> 5:×:3 `elem` [1:×:2, 9:×:4, 7:×:6]
False
>> find (== 5:×:3) [1:×:2, 3:×:4, 5:×:6]
Just (3 :×: 4)
>> find (== 5:×:3) [1:×:2, 9:×:4, 7:×:6]
Nothing