我有一个这种格式的列表[(Int,[(Int,Int,Float)])]。 它是一个图表上的节点及其边缘列表。列表的每个元组包含: (节点,[(startNode,endNode,Weight)])。我喜欢做的是创建所有节点的列表。我尝试过使用:
nodes xs = map fst xs
但它不起作用,我不知道为什么。有什么建议吗?
编辑: 更具体地说,这些是我正在使用的数据结构
data Graph = G [(Node, [Edge])]
data Node = N Integer
type Edge = ( Node, Node, Float )
答案 0 :(得分:2)
您需要从Graph
数据类型中解包数据以对其进行操作。最简单的方法是做一些像
mapG :: ([(Node, [Edge])] -> a) -> Graph -> a
mapG f (G nodes) = map f nodes
然后您可以将其用作
> let xs = G [(N 1, []), (N 2, [])]
> mapG fst xs
[N 1, N 2]
Graph
的类型不是列表,它是列表的包装器。您可能会考虑仅使用类型别名,因为您没有使用Haskell数据类型的任何功能,更像是
type Edge = (Node, Node, Float)
type Node = Integer
type Graph = [(Node, [Edge])]
然后你可以轻松做到
> let xs = [(1, []), (2, [])] :: Graph
> :type xs
xs :: Graph
> map fst xs
[1, 2]
因此,快速概述Haskell中的类型。声明可以在类型签名中使用的内容有4种主要方式:type
,newtype
,data
和class
。
type
最容易理解,宣称为type
的任何内容都只是一个别名。所以
type Node = Integer
与Integer
本身完全相同。它可以在任何使用Integer
的地方使用,反之亦然。所有这些构造都是为了让您的意图更加清晰,例如预定义的FilePath
类型,它是String
的别名。如果你看到一个功能
writeToFile :: String -> String -> IO ()
与
相比writeToFile :: FilePath -> String -> IO ()
你在第二个中立即知道第一个参数是文件路径,而不必查看其他任何内容。类型也可用于为更复杂的类型创建同义词,例如
type Edge = (Node, Node, Float)
现在你可以在任何你想要这个元组的地方写Edge
,它更加简洁易懂。 type
也可以参数化
type List a = [a]
通过使用type
,您还可以获取所有类别实例的所有类型类实例,例如,您可以将两个Node
与常用的+
一起添加取回Node
。
newtype
type
稍微更强大的版本,newtype
必须遵循特定的形式。他们有一个单一类型的构造函数,通常用作别名,你不希望人们能够真正看到里面的东西。例如:
newtype MyInt = MyInt Int
创建一个名为MyInt
的类型,其中包含Int
类型的单个值。这在编译时(几乎总是)优化掉,因此一旦程序运行MyInt
占用与Int
相同的内存,但在编译时MyInt
和Int
可以不可互换使用。这些在以后变得非常有用。与type
一样,它们可以参数化,但与类型不同,您不能免费获取实例。 MyInt
默认情况下不会实现Num
,因此您无法将它们添加到一起。
data
这是一个非常复杂的主题,所以我会说很多。 data
类型是全新的,而不仅仅是别名。它可以有一个或多个构造函数,每个构造函数需要0个或多个参数。 Bool
是一种具有2个构造函数的数据类型,每个构造函数都有0个参数:
data Bool = False | True
Maybe
有两个构造函数,但有一个构造函数:
data Maybe a = Nothing | Just a
在这里,我们看到Maybe
也参数化了。这些data
类型也不实现其内容的类型类实例,因为通常这是不可能的。您还可以为data
类型提供多个参数,例如
data Either a b = Left a | Right b
如果您有类似
的数据类型data Node = N Integer
然后Integer
与Node
的类型不同,反之亦然。要将Integer
转换为Node
,您必须使用N
构造函数。您可以将构造函数视为一种特殊的函数,甚至可以在GHCi中询问它们的类型:
> :type Just
Just :: a -> Maybe a
class
这是最抽象的一个。类型类没有直接定义类型,而是为类型类的实例提供了一种原型。例如,Eq
类型类基本上定义为
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
a /= b = not (a == b)
这里Eq
表示实现此类的类型必须为函数(==)
提供定义,并且可以选择提供(/=)
的定义,但是有一个默认实现你不提供它的情况。 data Node
可以将其实现为
instance Eq Node where
(N a) == (N b) = a == b
Haskell类型系统有足够的信息,细节和扩展,您可以填写一些书籍,因此不要期望这种形式是全面的。我甚至没有提到过整个主题,但这应该是一个很好的入门书。
至于产生边缘,这取决于你。我不知道您的图表用途是什么,或者您希望将哪些数据放入其中,因此我认为我无法真正帮助您。