如何将列表元素分隔为Char或Float

时间:2019-03-24 14:18:36

标签: haskell

当我从char和float中提取一棵混合树时,我必须将它们作为haskell中的Float或Character分开,并将它们添加到特定的列表中,我试图编写一些内容,如下所示;

我试图在else部分中将as作为[a],但它也给出了错误。

data BETree = Leaf Float | Node Char BETree BETree deriving (Show, Ord, Eq)

charList :: [Char]
charList = []

floatList :: [Float]
floatList = []

toList :: BETree -> ([Float], [Char])
toList (Node a l r) = if (a :: Char ) then (charList ++ [a])
                      else (floatList ++ a)

我希望输入的值对于floatList和charList是分开的,但是我得到这样的错误; 无法将预期类型“ [[Char]]”与实际类型“ Char”匹配 要么 反之亦然

1 个答案:

答案 0 :(得分:1)

您还没有掌握Haskell的几个方面,它们给您带来一些困难。

首先,您可能知道,Haskell非常重视其类型。这是一种强类型的语言,这意味着搜索整个数据结构以查找特定类型的值的整个概念是对这个问题的错误思考方式。 BETree的定义是:

data BETree = Leaf Float | Node Char BETree BETree deriving (Show, Ord, Eq)

,该结构由包含Leaf的{​​{1}}和包含Float的内部Node组成。因此,如果要查找所有Char值,则无需检查类型,只需查找Char。根据{{​​1}}的定义,它们都将包含Node,并且不能包含其他任何内容。换句话说,在您的函数定义中:

Char

您无需尝试检查BETree的类型-toList (Node a l r) = ... 定义中的a定义保证为Char。如果您单独写一个定义:

Node

然后,您可以类似地保证BETreetoList (Leaf x) = ... ,并且无需检查任何类型。

第二,Haskell通常使用不可变值。这意味着,与大多数其他语言不同,您通常不要先创建一个空列表,然后尝试在单独的函数中向其添加元素。取而代之的是,您通常编写递归函数,以返回“到目前为止的列表”,这些函数是通过向递归调用自身返回的列表中添加一个或多个元素来生成的。举一个简单的例子,要编写一个在输入列表中构建所有正整数列表的函数,您将编写:

x

所以。从 just 构建Float的较简单问题开始,这就是解决问题的方法:

positiveInts :: [Int] -> [Int]
positiveInts (x:xs) | x > 0 = x : positiveInts xs  -- add "x" to list from recursive call
                    | otherwise = positiveInts xs  -- drop "x"
positiveInts [] = []

并对其进行测试:

floatList

仅构建toFloatList :: BETree -> [Float] toFloatList (Leaf x) = [x] -- x is guaranteed to be a Float, so return it toFloatList (Node _a l r) = -- _a can't be a float, so ignore it toFloatList l ++ toFloatList r -- but recurse to find more Floats in Leafs 稍微复杂一点:

> toFloatList (Node 'x' (Leaf 1.0) (Node 'y' (Leaf 3.0) (Leaf 4.0)))
[1.0,3.0,4.0]
>

并对其进行测试:

charList

在Haskell中,字符toCharList :: BETree -> [Char] toCharList (Leaf _x) = [] -- x is guaranteed to be a Float, so no Chars here toCharList (Node a l r) = -- "a" is a Char toCharList l ++ [a] ++ toCharList r -- recurse and put "a" in the middle 的列表与字符串> toCharList (Node 'x' (Leaf 1.0) (Node 'y' (Leaf 3.0) (Leaf 4.0))) "xy" > "xy" == ['x','y'] True > 等效,这就是为什么它以这种方式打印的原因。

现在,定义['x','y']的最简单方法是:

"xy"

这遍历了两次树。如果要一次遍历两个列表,则事情会变得更加复杂:

toList

和测试:

toList :: BETree -> ([Float], [Char])
toList bet = (toFloatList bet, toCharList bet)