使用列表理解在 Haskell 中创建新类型列表
Using list comprehension to make a list of new type in Haskell
我正在尝试创建一个函数,returns 我从两个列表中定义的关联类型列表。我考虑使用列表理解,但我不确定如何从每个列表中获取值。
type Assoc k v = [(k, v)]
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc k v =
[Assoc k' v' | k' <- k, ???]
main :: IO ()
main = do
putStrLn $ show makeAssoc [1,2,3] [4,5,6]
如何实现makeAssoc k v
?
您已将 Assoc k v
定义为 [=19] 列表的别名(type
不会创建不同的类型,只是给现有类型一个新名称 - 它们仍然可以互换) =].根据 makeAssoc 类型签名,它 returns 是一个 Assoc k v
的列表。这意味着它实际上 returns 是 (k, v)
列表的列表,而这可能不是您想要的。两种可能的解决方案:
解决方案 1 - 将 Assoc k v
保留为元组列表并从 makeAssoc
的类型签名中删除 []
type Assoc k v = [(k, v)]
makeAssoc :: [k] -> [v] -> Assoc k v
解决方案 2 - 使 Assoc k v
成为元组的别名(不是元组列表)并在 makeAssoc
的类型签名中保留 []
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
另一个问题是 type Assoc k v
创建了可以在类型签名上使用的别名 Assoc k v
,但它没有创建具有相应数据构造函数的实际不同类型。所以你不能在函数的实际实现上使用 Assoc k v
。这意味着我们正在使用简单的元组,列表理解的正确语法是(使用之前的第二个解决方案):
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = [(k, v) | k <- ks, v <- vs]
但是列表理解会使用每个列表中的一个元素为您提供所有可能的对。示例:makeAssoc [1, 2] [3, 4]
将导致 [(1, 3), (1, 4), (2, 3), (2, 4)]
。如果你真的想要一对一的直接映射,你应该使用 zip
.
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = zip ks vs
使用此实现,结果将是 [(1, 3), (2, 4)]
。
编辑:
更进一步:当您在 Haskell 方面获得更多经验时,您将了解到您可以编写与以下内容相同的内容:
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc = zip
另一件事:如果你想要一个实际的不同类型,你可以使用 data
关键字和 zipWith
函数。
data Assoc k v = Assoc k v
deriving (Show)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = zipWith Assoc ks vs
或像以前一样省略参数:
data Assoc k v = Assoc k v
deriving (Show)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc = zipWith Assoc
Learn you a Haskell 对于初学者来说是一个很好的资源,应该可以帮助您理解所有这些以及更多。
我正在尝试创建一个函数,returns 我从两个列表中定义的关联类型列表。我考虑使用列表理解,但我不确定如何从每个列表中获取值。
type Assoc k v = [(k, v)]
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc k v =
[Assoc k' v' | k' <- k, ???]
main :: IO ()
main = do
putStrLn $ show makeAssoc [1,2,3] [4,5,6]
如何实现makeAssoc k v
?
您已将 Assoc k v
定义为 [=19] 列表的别名(type
不会创建不同的类型,只是给现有类型一个新名称 - 它们仍然可以互换) =].根据 makeAssoc 类型签名,它 returns 是一个 Assoc k v
的列表。这意味着它实际上 returns 是 (k, v)
列表的列表,而这可能不是您想要的。两种可能的解决方案:
解决方案 1 - 将 Assoc k v
保留为元组列表并从 makeAssoc
type Assoc k v = [(k, v)]
makeAssoc :: [k] -> [v] -> Assoc k v
解决方案 2 - 使 Assoc k v
成为元组的别名(不是元组列表)并在 makeAssoc
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
另一个问题是 type Assoc k v
创建了可以在类型签名上使用的别名 Assoc k v
,但它没有创建具有相应数据构造函数的实际不同类型。所以你不能在函数的实际实现上使用 Assoc k v
。这意味着我们正在使用简单的元组,列表理解的正确语法是(使用之前的第二个解决方案):
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = [(k, v) | k <- ks, v <- vs]
但是列表理解会使用每个列表中的一个元素为您提供所有可能的对。示例:makeAssoc [1, 2] [3, 4]
将导致 [(1, 3), (1, 4), (2, 3), (2, 4)]
。如果你真的想要一对一的直接映射,你应该使用 zip
.
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = zip ks vs
使用此实现,结果将是 [(1, 3), (2, 4)]
。
编辑:
更进一步:当您在 Haskell 方面获得更多经验时,您将了解到您可以编写与以下内容相同的内容:
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc = zip
另一件事:如果你想要一个实际的不同类型,你可以使用 data
关键字和 zipWith
函数。
data Assoc k v = Assoc k v
deriving (Show)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = zipWith Assoc ks vs
或像以前一样省略参数:
data Assoc k v = Assoc k v
deriving (Show)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc = zipWith Assoc
Learn you a Haskell 对于初学者来说是一个很好的资源,应该可以帮助您理解所有这些以及更多。