基本上我想做这样的事情:(哪些不起作用)
g2 (x:xs) = x
g2 ((x:xs):ys) = x
因此,如果g2获得一个列表,它应该提取列表的第一个元素,如果它是一个列表列表,它应该提取第一个列表中的第一个元素。
答案 0 :(得分:2)
详细说明Willem Van Onsem所说的内容,如果你注释你的功能,你会得到:
-- aka `head`
g2 :: [a] -> a
g2 (x:xs) = x
-- aka `head . head`
g2' :: [[a]] -> a
g2' ((x:xs):ys) = x
这些功能不能相同,因为如果g2
有时作为输入[a]
而有时作为输入[[a]]
,那么GHC会尝试统一a = [a]
, GHC无限调用无限类型(a = [a]
⇒a = [[a]]
⇒a = [[[...a...]]]
。
当你想要一个有时候是列表而有时候是列表列表的函数时,Haskell会使用求和类型处理它,例如
g2 :: Either [a] [[a]] -> a
g2 (Left (x:xs)) = x
g2 (Right ((x:xs):ys)) = x
并且在任何输入上使用此功能之前,您必须知道它是哪一个(例如Left "Hello"
,Right ["Hello", "World"]
)。但要注意到目前为止所有的g2
都是partial,这很糟糕。例如。调用g2 (Left [])
,g2 (Right [])
或g2 [Right [[]]
会崩溃。
如果您没有列表,而是有一个n-ary树(Data.Tree
),
import Data.Tree
然后这可以让你任意嵌套列表:
g2 :: Tree a -> a
g2 (Tree x []) = x
g2 (Tree _ (Tree x : _)) = x
或者您甚至可以获得第一棵树的第一个元素,没有子森林,或者最多n
深:
g :: Int -> Tree a -> a
g 0 (Tree x _) = x
g _ (Tree x []) = x
g n (Tree _x t) = g (n-1) t
g2 :: Tree a -> a
g2 = g 1
由于Tree a
的定义方式,这种树不能为空,因此g2
不是部分的。与[[a]]
不同,Tree a
在树的顶层(例如上面的x
)和_x
中的另一个级别都有x
。< / p>
如果你(a)打算让你的输入只嵌套两个深,(b)“父值”的概念没有意义你的情况和(c)你希望在类型级别保证你所寻找的x
存在,也许最好是撰写Data.List.NonEmpty
:< / p>
import Data.List.NonEmpty
type NestedNonEmpty a = Either (NonEmpty a) (NonEmpty (NonEmpty a))
g2 :: NestedNonEmpty a -> a
g2 (Left (x :| _)) = x
g2 (Right ((x :| _) :| _)) = x
然后您就可以使用它:
onetwothree :: NonEmpty Int
onetwothree = 1 :| 2 : 3 : []
t1, t2 :: NestedNonEmpty Int
t1 = Left onetwothree
t2 = Right $ onetwothree :| fmap (+3) onetwothree : []
demo1, demo2 :: Int
demo1 = g2 t1 -- 1
demo2 = g2 t2 -- 1
但是由于这种数据类型过于具体,或许最好修改输入实际看起来的内容,然后修改它的类型。既然你评论说你必须找到另一种方法来解决你的问题,或许可以问一个关注那个问题的问题,不要把它变成X-Y problem。 : - )