空列表问题的头函数

Aro*_*Lee 1 haskell list filter

我想在地图中使用'head'功能.问题是'head'函数只接受非空列表.我有清单列表:

let ll =[["dog", "cat"], ["pig", "cow"], []]
Run Code Online (Sandbox Code Playgroud)

我需要两次迭代列表列表

let listOne = filter(\x -> if length x > 0) ll
map(\x -> head x) listOne
Run Code Online (Sandbox Code Playgroud)

我想知道我是否可以迭代列表列表一次或在地图中放入"if condition"而不使用'filter'

任何建议将不胜感激.

Wil*_*sem 8

是的,实际上你可以把它写成列表理解语句,并使用模式匹配代替:

result = [ h | (h:_) <- ll ]
Run Code Online (Sandbox Code Playgroud)

或作为一种功能:

heads :: [[a]] -> [a]
heads ll = [ h | (h:_) <- ll ]
Run Code Online (Sandbox Code Playgroud)

所以这里我们使用(h:_)匹配所有非空列表的模式,我们直接获取h这样的列表的头部并将其添加到列表中.如果在列表推导中使用模式(在左箭头的左侧<-,它将跳过与模式不匹配的元素).

这比使用安全length,因为length如果使用无限列表,它将陷入无限循环.此外,通过使用非总head函数的模式,我们有更多的语法保证,这个函数将起作用(是的,一旦非空元素被过滤,我们当然肯定head不会导致错误,但我们只知道这个因为我们有关于这个head功能的信息).

请注意,您的尝试将导致语法错误,因为您使用的是a if,而不是a thenelsepart.

或者,我们可以像@DanielWagner所说的那样,以heads不同的方式编写函数,例如使用:

heads :: [[a]] -> [a]
heads ll = concatMap (take 1) ll
Run Code Online (Sandbox Code Playgroud)

或者使用list monad 的绑定:

heads :: [[a]] -> [a]
heads = (take 1 =<<)
Run Code Online (Sandbox Code Playgroud)

或者我们可以转置2d列表.在这种情况下,第一行包含列表的所有头部.但由于不能保证有这样的行,我们可以在末尾添加一个空列表,如:

heads :: [[a]] -> [a]
heads = head . (++ [[]]) . transpose
Run Code Online (Sandbox Code Playgroud)

  • 另一个有趣的拼写:`heads = concatMap(take 1)`.一个完全不同的想法:`head = head.(++ [[]]).transpose`. (2认同)