Control.Applicative提升n列表

时间:2016-09-11 14:47:20

标签: haskell

我对Haskell很陌生,并且想知道如何在不使用固定理解列表(或者实际上是像liftA这样的应用函子)的情况下实现以下输出,即

require_once ('db.php');

if (array_key_exists('check_submit', $_POST)) {

    $userFile = $_FILES['cv']['name'];
    $tmp_dir = $_FILES['cv']['tmp_name'];
    $fileSize = $_FILES['cv']['size'];

    if (empty($userFile)) {
       echo  $errMSG = "Please Select File.";
    } else {
        $upload_dir = './files/'; // upload directory

        $fileExt = strtolower(pathinfo($userFile, PATHINFO_EXTENSION)); // get file extension

        // valid image extensions
        $valid_extensions = array('doc', 'docx', 'pdf', 'ppt','pptx','txt','jpeg','jpg','png'); // valid extensions

        // rename uploading image
        $userFileName = rand(1000, 1000000) . "." . $fileExt;

        // allow valid image file formats
        if (in_array($fileExt, $valid_extensions,$fileSize <= 10000000) ){
            // Check file size '10MB
            move_uploaded_file($tmp_dir, $upload_dir . $userFileName);
        } else {
              echo $errMSG = "Sorry, your file is too large or its not JPG JPEG PNG PDF DOC DOX TXT.";
        }
    }
}
if(!isset($errMSG)) {
    $stmt = $DB_con->prepare('INSERT INTO files (filename) VALUES(:filename)');
    $stmt->bindParam(':filename',$userFileName);
    if($stmt->execute())
    {
        $successMSG = "new record succesfully inserted ...";
        header("refresh:5;index.php"); 
    }
    else
    {
        $errMSG = "error while inserting....";
    }
}

以上代码示例仅处理3个列表,例如XYZ。如何使用n个列表实现相同的功能,例如:例如[[1,11]]或[[1,11],[1,11],[1,11],[1,11],[1,11]]?

PS - 我查看了使用控制器Applicative functor liftA,但仅限于liftA3,例如

if ( is_front_page() && is_home() ) {
  // Default homepage
}

感谢。

3 个答案:

答案 0 :(得分:3)

如果您使用同一列表[1,11] n 副本,则可以使用replicateM

import Control.Monad

ghci> replicateM 3 [1,11]
[[1,1,1],[1,1,11],[1,11,1],[1,11,11],[11,1,1],[11,1,11],[11,11,1],[11,11,11]]

ghci> map sum (replicateM 3 [1,11])
[3,13,13,23,13,23,23,33]

通常,您可以使用sequence执行多列表笛卡尔积:

ghci> sequence [ [1,11], [2,22], [3,33] ]
[[1,2,3],[1,2,33],[1,22,3],[1,22,33],[11,2,3],[11,2,33],[11,22,3],[11,22,33]]

答案 1 :(得分:0)

如果您希望灵活处理输入,而不仅仅是[1,11] 的列表:

λ> import Control.Applicative (liftA2)
λ> let sumsOfCombinations xs = (:[]) . sum <$> foldr (liftA2 (:)) [[]] xs

您可以将任何数字列表传递给它:

λ>  sumsOfCombinations' [[0,100],[-1,0,1],[0,1000]]
[-1,999,0,1000,1,1001,99,1099,100,1100,101,1101]

包括但不限于,您的示例:

λ> sumsOfCombinations $ replicate 3 [1,11]
[[3],[13],[13],[23],[13],[23],[23],[33]]

λ> sumsOfCombinations $ replicate 4 [1,11]
[[4],[14],[14],[24],[14],[24],[24],[34],[14],[24],[24],[34],[24],[34],[34],[44]]

这是它的类型:

λ> :t sumsOfCombinations
sumsOfCombinations :: (Num b, Foldable t) => t [b] -> [[b]]

正如所写,sumsOfCombinations为您提供了您正在寻找的确切输出。但是,我认为没有必要返回列表列表,所以我会选择:

λ> let sumsOfCombinations' xs = sum <$> foldr (liftA2 (:)) [[]] xs

λ> :t sumsOfCombinations'
sumsOfCombinations' :: (Num b, Foldable t) => t [b] -> [b]

λ> sumsOfCombinations' $ replicate 3 [1,11]
[3,13,13,23,13,23,23,33]

请注意,您可以从每个提取器中提取帮助器,以便为您提供列表中元素的组合:

λ> let combinations = foldr (liftA2 (:)) [[]]
λ> combinations [[1,2],[3,4],[5,6]]
[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]

那么你有:

sumsOfCombinations xs = (:[]) . sum <$> combinations xs

或者,如果您不需要返回列表列表:

sumsOfCombinations' xs = sum <$> combinations xs

答案 2 :(得分:0)

更一般地说,你想要的是给定列表中所有列表的笛卡尔积。一旦你拥有了它,你就可以以任何你喜欢的方式组合它们。

cartesian :: [[a]] -> [[a]]
cartesian [] = [[]]
cartesian (xs:xss) = [x : ys | x <- xs, ys <- cartesian xss]

mkSums :: [[Int]] -> [[Int]]
mkSums = map ((\x -> [x]) . sum) . cartesian