从元组列表中获取第一个元素

时间:2014-03-20 21:53:02

标签: haskell functional-programming ghci

我有一个这种格式的列表[(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 )

1 个答案:

答案 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种主要方式:typenewtypedataclass

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相同的内存,但在编译时MyIntInt可以不可互换使用。这些在以后变得非常有用。与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

然后IntegerNode的类型不同,反之亦然。要将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类型系统有足够的信息,细节和扩展,您可以填写一些书籍,因此不要期望这种形式是全面的。我甚至没有提到过整个主题,但这应该是一个很好的入门书。


至于产生边缘,这取决于你。我不知道您的图表用途是什么,或者您希望将哪些数据放入其中,因此我认为我无法真正帮助您。