运用haskell,类型定义和守卫

时间:2010-01-13 13:58:38

标签: haskell

第一个问题:
定义一个使用分隔符值将列表列表连接在一起的函数 类型定义应该是这样的:

intersperse :: a -> [[a]] -> [a]

分隔符应出现在列表的元素之间,但不应该跟在最后一个元素之后 您的函数应该表现如下:


ghci> :load Intersperse
[1 of 1] Compiling Main             ( Intersperse.hs, interpreted )
Ok, modules loaded: Main.
ghci> intersperse ',' []
""
ghci> intersperse ',' ["foo"]
"foo"
ghci> intersperse ',' ["foo","bar","baz","quux"]
"foo,bar,baz,quux"

一段时间后我设法解决它:


intersperse myChar lists
    | lists == []          = ""  
    | otherwise            = attach myChar lists
        where   attach myChar (x:[]) = x 
                attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs 

但是,正如您所见,它没有类型定义 如果我将类型定义放在函数上方,我会收到错误。 为什么呢?

第二个问题:
在我得到这个解决方案之前,我想把另一名警卫放在警卫名单中。 这个quard应该是在第一个后卫之后。 我想检查列表变量中是否只有一个列表,所以我只返回列表变量。 但我不能做那样的警卫(再一次,错误就是生命: - )):


| lists == (x:[]) = lists

这也不起作用:


| lists == (_:[]) = lists
为什么为什么? :-)。

在此之后,我试图让其他警卫:


| length lists == 1    = lists

但它也引发了一个错误。

(顺便说一句,我不需要那些警卫,因为我发现“where”关键字之后的第一个模式,正是我想要的。
这就是我所说的模式:
   附上myChar(x:[])= x

但是,我仍然想知道为什么我试过的调子,不起作用。 另外,我找到了这个解决方案,运气好,我不认为每次我会注意到这样的事情:-)

非常感谢: - )。

P.S。 本练习来自书籍real world haskell

4 个答案:

答案 0 :(得分:3)

  1. ""的类型为[Char],但您的类型签名称intersperse会返回[a],其中a取决于输入类型,所以类型不匹配。

  2. 我认为你不能在守卫内部进行模式匹配。

    对于这个警卫

    | length lists == 1    = lists
    

    lists的类型为[[a]],但您应该返回[a]。也就是说,如果lists["foo"],则您希望返回"foo"。您不想返回["foo"]

答案 1 :(得分:2)

问题是你的函数不是通用的,它只适用于字符串(Char列表)。如果您将第二行更改为

lists == []          = []

你会得到你想要的东西,尽管由于equals运算符而依赖于Eq类型类。它甚至可以用于字符串,因为所有字符串都是列表,但并非所有列表都是字符串。

顺便说一句,您可以通过使用模式匹配来进一步概括您的功能:

intersperse myChar lists = case lists of
    []      -> []
    lists   -> attach myChar lists
    where   attach myChar (x:[]) = x 
            attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs 

或者,更具惯用性:

intersperse _ [] = []
intersperse x xs = attach x xs
    where   attach myChar (x:[]) = x 
            attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs

摆脱内在功能:

intersperse _ [] = []
intersperse _ (xs:[]) = xs
intersperse x (xs:xss) = (xs ++ x:intersperse x xss)

关于第二个问题,你在守卫中使用的等于运算符需要双方的值。你不能模仿匹配它。也许你正在寻找的东西就像这里的第二个改进。

答案 2 :(得分:1)

这会引起错误。
为什么? 除了你用case of写它之外,它和你一样。


intersperse :: a -> [[a]] -> [a]
intersperse myChar lists
    | lists == []          = []  
    | otherwise            = attach myChar lists
        where   attach myChar (x:[]) = x 
                attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs

这不会引发错误(这是你所分割的):


intersperse :: a -> [[a]] -> [a]
intersperse myChar lists = case lists of
    []      -> []
    lists   -> attach myChar lists
    where   attach myChar (x:[]) = x 
            attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs

但是在我的例子中(这里的第一个功能),我将守卫改为你建议的,但我仍然得到一个错误。

为什么会这样?

非常感谢。

答案 3 :(得分:0)

这可能是错误的,但它似乎可行

intersperse :: a -> [[a]] -> [a]
intersperse _ []             = []
intersperse separator [xs]   = xs
intersperse separator (x:xs) = x ++ [separator] ++ (intersperse separator xs)