Haskell 如何检查(字符串对列表和(字符串列表))中的字符串?

Haskell 如何检查(字符串对列表和(字符串列表))中的字符串?,haskell,Haskell,我有一个叫做“样本”的数据,定义为 data Sample = Test1 (String,[[String]]) | Test2 (String,[[String]]) 然后我创建一个名为“Samples”的列表[Sample],比如 现在,我需要检查“Sample3”下是否存在“aborts”。我有一个基本的 我知道如何做,但我不知道如何在Haskell中实现它 我的想法是 check:: String -> [String] -> [Sample]

我有一个叫做“样本”的数据,定义为

data Sample = Test1 (String,[[String]])
             | Test2 (String,[[String]])
然后我创建一个名为“Samples”的列表[Sample],比如

现在,我需要检查“Sample3”下是否存在“aborts”。我有一个基本的 我知道如何做,但我不知道如何在Haskell中实现它

我的想法是

check:: String -> [String] -> [Sample] -> Bool
check samplename result samples =
我可以这样称呼它:

check "Sample3" ["aborts"] Samples
但是我如何实现这个功能呢


我已经这样解决了,但我正在寻找一个更好的版本

我的版本是:

check:: String -> [String] -> [Sample] -> Bool
check samplename result samples = 
  if( "True" `elem` final ) 
  then True 
  else False
    where 
      final = [x | sample <- samples, 
                   x <- [ case sample of
                               Test1 (name,res) = 
                                 if name == samplename && (result `elem` res) 
                                 then "True" 
                                 else "False"
                               Test2 (name, res) = "False"]]
check::String->[String]->[Sample]->Bool
检查samplename结果样本=
if(“True”`elem`final)
那是真的
否则错误
哪里

final=[x | sample这应该可以做到:

data Sample = Test1 String [[String]]
            | Test2 String [[String]]

sampleName :: Sample -> String
sampleName (Test1 name _) = name
sampleName (Test2 name _) = name

getData :: Sample -> [[String]]
getData (Test1 _ samples) = samples
getData (Test2 _ samples) = samples

check :: String -> [String] -> [Sample] -> Bool
check name needle samples = any doCheck samples
  where
    doCheck s = if sampleName s == name
                then needle `elem` getData s
                else False
如果所有名称都应该是不同的,则可以更快地中止搜索:

check2 :: String -> [String] -> [Sample] -> Bool
check2 name needle samples = go samples
  where
    go []     = False
    go (s:ss) = if sampleName s == name
                then needle `elem` getData s
                else go ss
测试:

*Main> check "Sample3" ["aborts"] tst
True

对您的版本的评论:

data Sample = Test1 (String,[[String]])
             | Test2 (String,[[String]])
这里不需要元组(参见我的代码)

一般来说,
如果expr那么True或者False总是可以替换为
expr
。为什么使用字符串作为布尔值

final = [x | sample <- samples,
         x <- [ case sample of
                   Test1 (name,res) -> if name == samplename
                                         && (result `elem` res)
                                      then "True" else "False"
                   Test2 (name, res) -> "False"]]

这应该可以做到:

data Sample = Test1 String [[String]]
            | Test2 String [[String]]

sampleName :: Sample -> String
sampleName (Test1 name _) = name
sampleName (Test2 name _) = name

getData :: Sample -> [[String]]
getData (Test1 _ samples) = samples
getData (Test2 _ samples) = samples

check :: String -> [String] -> [Sample] -> Bool
check name needle samples = any doCheck samples
  where
    doCheck s = if sampleName s == name
                then needle `elem` getData s
                else False
如果所有名称都应该是不同的,则可以更快地中止搜索:

check2 :: String -> [String] -> [Sample] -> Bool
check2 name needle samples = go samples
  where
    go []     = False
    go (s:ss) = if sampleName s == name
                then needle `elem` getData s
                else go ss
测试:

*Main> check "Sample3" ["aborts"] tst
True

对您的版本的评论:

data Sample = Test1 (String,[[String]])
             | Test2 (String,[[String]])
这里不需要元组(参见我的代码)

一般来说,
如果expr那么True或者False总是可以替换为
expr
。为什么使用字符串作为布尔值

final = [x | sample <- samples,
         x <- [ case sample of
                   Test1 (name,res) -> if name == samplename
                                         && (result `elem` res)
                                      then "True" else "False"
                   Test2 (name, res) -> "False"]]

如果我们在高层次上考虑检查必须做什么,我们知道它必须检查样本的每个元素,以查看测试“Sample3”是否包含任何(或全部,我不清楚您的意思是什么)字符串结果

所以我们知道我们需要递归,我们可以从函数的大致轮廓开始:

 check :: String -> [String] -> [Sample] -> Bool
 check samplename result []     = False
 check samplename result (x:xs) = ...
因此,当列表为空时,不会出现匹配项,因此我们可以立即返回false。在递归情况下,我们知道需要检查x,如果没有找到匹配项,则继续检查xs。一种可能的方法是使用helper函数检查(您也可以直接内联检查)

好的,那么check做什么呢?它检查数据类型样本以查看是否存在任何匹配。我们知道样本有两个构造函数,Test1Test2所以check应该是这样的

 check' :: Sample -> Bool
 check' (Test1 (name, values)) = ...
 check' (Test2 (name, values)) = ...
我们要做的第一件事是测试name的值,看看它是否与samplename匹配。我们可以使用警卫轻松地完成这项工作

 check' :: Sample -> Bool
 check' (Test1 (name, values)) | name == samplename = ...
 check' (Test2 (name, values)) | name == samplename = ...
 check' _                                           = False
由于check'是check的子函数,因此check中定义的变量在作用域中,因此我们可以直接引用它们。添加了一个新的大小写来处理名称不匹配的事件

好的,现在的想法是检查结果中的任何(或所有)值是否出现在值中。幸运的是,前奏曲有一个函数可以用于此

elem :: Eq a => a -> [a] -> Bool
该函数现在变为

 check' :: Sample -> Bool
 check' (Test1 (name, values)) | name == samplename = result `elem` values
 check' (Test2 (name, values)) | name == samplename = result `elem` values
 check' _                                           = False
因此,其全部功能是:

check :: String -> [String] -> [Sample] -> Bool
check samplename result []     = False
check samplename result (x:xs) = check' x || check samplename result xs
   where check' :: Sample -> Bool
         check' (Test1 (name, values)) | name == samplename = result `elem` values
         check' (Test2 (name, values)) | name == samplename = result `elem` values
         check' _                                           = False
使用谓词检查列表中的每个元素非常常见,因此prelude具有用于此操作的标准函数。定义检查的一种可能方法是使用函数映射。 这通常会导致效率较低的功能,尽管:

check :: String -> [String] -> [Sample] -> Bool
check samplename result samples = or (map check' samples)
   where check' :: Sample -> Bool
         check' (Test1 (name, values)) | name == samplename = result `elem` values
         check' (Test2 (name, values)) | name == samplename = result `elem` values
         check' _                                           = False
通过为数据类型调整替代结构,可以进一步简化该函数,例如

type ID     = Int
type Name   = String
type Values = [[String]]
data Sample = Test ID Name Values
然后,该函数变为

check :: String -> [String] -> [Sample] -> Bool
check samplename result samples = or (map check' samples)
   where check' :: Sample -> Bool
         check' (Test _ name values) | name == samplename = result `elem` values
         check' _                                         = False
最后,由于check的结果是Bool,而警卫也是Bool,因此我们可以将check重构为一种更简单的形式,而不需要使用错误案例

check :: String -> [String] -> [Sample] -> Bool
check samplename result samples = or (map check' samples)
   where check' :: Sample -> Bool
         check' (Test _ name values) = name == samplename && result `elem` values
这种**或(映射…)**模式非常常见,因此也有一个前奏功能any可以实现这一点。检查可以进一步简化为

check :: String -> [String] -> [Sample] -> Bool
check samplename result samples = any check' samples
   where check' :: Sample -> Bool
         check' (Test _ name values) = name == samplename && result `elem` values

如果我们在高层次上考虑检查必须做什么,我们知道它必须检查样本的每个元素,以查看测试“Sample3”是否包含任何(或全部,我不清楚您的意思是什么)字符串结果

所以我们知道我们需要递归,我们可以从函数的大致轮廓开始:

 check :: String -> [String] -> [Sample] -> Bool
 check samplename result []     = False
 check samplename result (x:xs) = ...
因此,当列表为空时,不会出现匹配项,因此我们可以立即返回false。在递归情况下,我们知道需要检查x,如果没有找到匹配项,则继续检查xs。一种可能的方法是使用helper函数检查(您也可以直接内联检查)

好的,那么check做什么呢?它检查数据类型样本以查看是否存在任何匹配。我们知道样本有两个构造函数,Test1Test2所以check应该是这样的

 check' :: Sample -> Bool
 check' (Test1 (name, values)) = ...
 check' (Test2 (name, values)) = ...
我们要做的第一件事是测试name的值,看看它是否与samplename匹配。我们可以使用警卫轻松地完成这项工作

 check' :: Sample -> Bool
 check' (Test1 (name, values)) | name == samplename = ...
 check' (Test2 (name, values)) | name == samplename = ...
 check' _                                           = False
由于check'是check的子函数,因此check中定义的变量在作用域中,因此我们可以直接引用它们。添加了一个新的大小写来处理名称不匹配的事件

好的,现在的想法是检查结果中的任何(或所有)值是否出现在值中。幸运的是,前奏曲有一个函数可以用于此

elem :: Eq a => a -> [a] -> Bool
该函数现在变为

 check' :: Sample -> Bool
 check' (Test1 (name, values)) | name == samplename = result `elem` values
 check' (Test2 (name, values)) | name == samplename = result `elem` values
 check' _                                           = False
因此,其全部功能是:

check :: String -> [String] -> [Sample] -> Bool
check samplename result []     = False
check samplename result (x:xs) = check' x || check samplename result xs
   where check' :: Sample -> Bool
         check' (Test1 (name, values)) | name == samplename = result `elem` values
         check' (Test2 (name, values)) | name == samplename = result `elem` values
         check' _                                           = False
使用谓词检查列表中的每个元素非常常见,因此prelude具有用于此操作的标准函数。定义检查的一种可能方法是使用函数映射。 这通常会导致效率较低的功能,尽管:

check :: String -> [String] -> [Sample] -> Bool
check samplename result samples = or (map check' samples)
   where check' :: Sample -> Bool
         check' (Test1 (name, values)) | name == samplename = result `elem` values
         check' (Test2 (name, values)) | name == samplename = result `elem` values
         check' _                                           = False
通过为数据类型调整替代结构,可以进一步简化该函数,例如

type ID     = Int
type Name   = String
type Values = [[String]]
data Sample = Test ID Name Values
然后,该函数变为

check :: String -> [String] -> [Sample] -> Bool
check samplename result samples = or (map check' samples)
   where check' :: Sample -> Bool
         check' (Test _ name values) | name == samplename = result `elem` values
         check' _                                         = False
最后,由于check的结果是Bool,而警卫也是Bool,因此我们可以将check重构为一种更简单的形式,而不需要使用错误案例

check :: String -> [String] -> [Sample] -> Bool
check samplename result samples = or (map check' samples)
   where check' :: Sample -> Bool
         check' (Test _ name values) = name == samplename && result `elem` values
这种**或(映射…)**模式非常常见,因此也有一个前奏功能any可以实现这一点。检查可以进一步简化为

check :: String -> [String] -> [Sample] -> Bool
check samplename result samples = any check' samples
   where check' :: Sample -> Bool
         check' (Test _ name values) = name == samplename && result `elem` values

这是我的解决方案。但我认为你的数据并不代表任何实际问题,如果你想存储像[Sample]这样的东西,你可以很容易地使用Map,它基本上是一个键值列表