Haskell列表理解-无效谓词

Haskell列表理解-无效谓词,haskell,list-comprehension,Haskell,List Comprehension,我对Haskell非常陌生(在当前程序之前只编写了一个fizzbuzz程序),我正在尝试编写一个程序,该程序采用unix单词列表('/usr/share/dict/words'),并打印出该单词的拼字列表,任何直接回文都加上星号。我把它的要点归纳为一个功能: findAnagrams :: [String] -> [(String, [String])] findAnagrams d = [x | x <- map (\s -> (s, [if reverse s == t

我对Haskell非常陌生(在当前程序之前只编写了一个fizzbuzz程序),我正在尝试编写一个程序,该程序采用unix单词列表('/usr/share/dict/words'),并打印出该单词的拼字列表,任何直接回文都加上星号。我把它的要点归纳为一个功能:

findAnagrams :: [String] -> [(String, [String])]
findAnagrams d =
  [x | x <- map (\s -> (s, [if reverse s == t then t ++ "*" else t | t <- d, s /= t && null (t \\ s)])) d, not (null (snd x))]
等等,很明显它不能正常工作。我的意图是让列表理解如下:对于d中的所有t,t不等于s,t和s之间除了顺序之外没有区别,如果t是s的倒数,则包括为t*,否则包括为t。问题似乎在于“除了顺序之外,t和s之间没有区别”部分,我试图通过使用“null(t\s)”来实现这一部分。看来应该行得通。GHCI中的测试给出:

Prelude Data.List> null ("abatements" \\ "abasements")
False
但它通过了谓词测试。我的假设是,我在这里遗漏了一些简单的东西,但我已经研究了一段时间,不能完全想出它


此外,任何关于最佳实践的注释都将不胜感激。

如果您将其分解为多个函数(请记住,源代码大小并不是那么重要),您可以执行以下操作:

import Data.List

isPalindrome :: String -> Bool
isPalindrome s = s == reverse s

flagPalins :: [String] -> [String]
flagPalins [] = []
flagPalins (x:xs)
    | isPalindrome x = x ++ "*"
    | otherwise      = x

isAnagram :: String -> String -> Bool
isAnagram s t = (isPalindrome s || s /= t) && ??? -- test for anagram

findAnagrams :: String -> [String] -> [String]
findAnagrams s ws = flagPalins $ filter (isAnagram s) ws

findAllAnagrams :: [String] -> [(String, [String])]
findAllAnagrams ws = filter (not . null . snd) ??? -- words paired with their anagrams
我故意留下了一些漏洞让你填补,我不会给你所有的答案;)

你只有两个地方可以自己做。
findAllAnagrams
中的一个应该很容易理解,您已经在使用
映射(\s->…)
部分执行类似的操作。我特意构造了
isAnagram
,因此如果它是回文或只是一个字谜,它将返回
True
,您只需要再检查一次就可以确定
t
是否是
s
的字谜。看看我对你的问题所做的评论,想知道在那里该做些什么。如果您遇到问题,请发表评论并询问其他提示,我将给出我认为您应该用于解决此问题的函数的名称



如果你真的想做一个列表理解,我建议用这种方法解决它,然后再转换回理解。一般来说,您应该编写更详细的代码,然后在完全理解后对其进行压缩。

a\\b
视为“a中不在
b
中的项目”


考虑一下其中的含义。

我运行了你的代码,但它没有给我那些字谜。再查一遍。关于风格,这条线很长。考虑把一些事情拉到他们自己的功能中。看起来你的主要问题是你如何检查字谜。你可以做什么其他类型的测试来检查两个单词是否有相同的字母,而不是做列表差异?顺序真的很重要吗,或者你能在比较之前改变字母的顺序吗?@TomEllis如果
d
包含多个字符串,尤其是字谜,那么代码工作得很好(嗯,也许还可以)!试试
findAnagrams[“bac”、“abc”、“cab”]
@groovy:的确,代码比特征值博士想象的要好,但bheklillr仍然是对的:代码是不正确的。正如这里的人所暗示的,列表理解并不是特别有用或惯用的。考虑将其分解为正常函数,使用<代码> map < /COD>和<代码>过滤器< /代码>。
import Data.List

isPalindrome :: String -> Bool
isPalindrome s = s == reverse s

flagPalins :: [String] -> [String]
flagPalins [] = []
flagPalins (x:xs)
    | isPalindrome x = x ++ "*"
    | otherwise      = x

isAnagram :: String -> String -> Bool
isAnagram s t = (isPalindrome s || s /= t) && ??? -- test for anagram

findAnagrams :: String -> [String] -> [String]
findAnagrams s ws = flagPalins $ filter (isAnagram s) ws

findAllAnagrams :: [String] -> [(String, [String])]
findAllAnagrams ws = filter (not . null . snd) ??? -- words paired with their anagrams