Haskell - 一个非常简单的功能

时间:2017-12-16 20:16:44

标签: list haskell

我试图理解以下功能:

SELECT 
    a.Marketplace, 
    a.ProdID, 
    a.MktID, 
    b.Title
FROM
    TableA a
        INNER JOIN
    TableB b ON a.Marketplace = b.Marketplace
        AND a.ProdID = b.ProdID

当输入这个:q1(地图abs [-1,-6,-5,7])时,它得到了我5.有人可以告诉我为什么会这样吗?我理解map函数如何,但模式匹配(x:_xs)有点令人困惑。谢谢!

1 个答案:

答案 0 :(得分:7)

Haskell中的列表 - 至少在概念上 - 是一个链表。有两种可能性:

  • 一个空列表[];或
  • a“cons”(x:xs)其中x head (第一项),xs tail (列表的其余部分)。

Haskell也使用语法糖。例如,[1]位于窗帘后面,翻译为(1:[])[1,4,2,5]改为(1:(4:(2:(5:[]))))

为什么这很重要?我们首先尝试理解q1函数。如果我们查看类型,我们会看到q1Int的列表作为输入,并返回Int。它以递归方式定义为:

q1 :: [Int]  -> Int
q1 [] = 0
q1 [x] = x
q1 (x:_:xs) = max x (q1 xs)

这意味着空列表的q1为零(0);具有一个元素q1的列表的xx。对于包含两个或更多元素的列表,该列表maximum的第一项的x和该列表的尾部 。这是因为我们将模式与(x:_:xs)匹配,(x:(_:xs))x的缩写。下划线基本上意味着“不关心”。所以列表应该是 cons ,其中尾部也是 cons ,我们对列表xs的头部和尾部感兴趣列表的尾部q1

如果我们对此进行推理,我们就会发现q1 (map abs [-1,-6,-5,7])返回奇数索引中元素的最大(所以第一,第三,第五)等元素)。如果列表具有偶数长度,我们还计算最大值为零(因此,如果奇数索引处的所有元素都是负数,则函数将返回零,但此如果我们有一个甚至长度的列表。

现在,如果用q1来调用它,则意味着我们会在map abs上的[-1, -6, -5, 7]结果上调用map absabs构造一个列表,其中map abs [-1, -6, -5, 7]应用于列表的所有元素(尽管它是懒惰应用的)。因此,在[1, 6, 5, 7]之后,我们获得了列表1。现在奇数索引处的元素是5q1。所以q2 :: (Num a, Ord a) => [a] -> a q2 [] = 0 q2 [x] = max 0 x q2 (x:_:xs) = max x (q2 xs) 将计算这些元素的最大值和零(因为列表的长度是4,这是偶数)。 max(0,1,5) 5

就个人而言,尤其是我们也认为零而且仅在列表具有偶数长度的情况下,非常“不稳定”。它可能导致难以理解的错误,因为它可能是函数细节的结果。我们可以例如用零计算最大值,无论列表的长度如何:

q3 :: Ord a => [a] -> a
q3 [x] = x
q3 [x,_] = x
q3 (x:_:xs) = max x (q3 xs)

或者我们可以决定不使用零,也不能在空列表中定义最大值,例如:

    $galleries = DB::table('galleries')->select( DB::raw('galleries.*') )
        ->where( 'domain_id', $domain_id )
        ->where( 'is_deleted', 0 )
        ->whereNotIn('id', array_keys( Session::get("export_selected"  ) ) )
        ->whereNotIn('id',             Session::get("export_skip"      )   )
        ->whereNotIn('id', array_keys( Session::get("export_delete"    ) ) )
        ->whereNotIn('id', array_keys( Session::get("export_delete_all") ) )
        ->leftJoin('history', function($join) use ( $site_id ) {
            $join->where('history.site_id', '=', $site_id )
                 ->on('history.gallery_id', '=', 'galleries.id');
        })
        ->whereNull('history.gallery_id')
        ->orderByRaw('RAND()')
        ->take(10)->get();