簡體   English   中英

Haskell:列表模式匹配

[英]Haskell: Pattern Matching with Lists

我正在嘗試創建一個接收列表的函數,如果其中一個元素為負,則該列表中與其正對應項相等的任何元素都應更改為 0。例如,如果有 -2在列表中,則該列表中的所有 2 都應更改為 0。

任何想法為什么它只適用於某些情況而不適用於其他情況? 我不明白這是為什么,我已經看了好幾遍了。

changeToZero [] = []
changeToZero [x] = [x]
changeToZero (x:zs:y:ws) | (x < 0) && ((-1)*(x) == y) = x : zs : 0 : changeToZero ws
changeToZero (x:xs) = x : changeToZero xs

changeToZero [-1,1,-2,2,-3,3]
-- [-1,1,-2,2,-3,3]

changeToZero [-2,1,2,3]
-- [-2,1,0,3]

changeToZero [-2,1,2,3,2]
-- [-2,1,0,3,2]

changeToZero [1,-2,2,2,1]
-- [1,-2,2,0,1]

我認為列表理解在這里更清晰、更容易。

changeToZero xs = [if x > 0 && (-x) `elem` xs then 0 else x | x <- xs]

如果您需要更有效的東西,您可以構建一組否定元素並檢查它而不是使用elem

import qualified Data.Set as Set

changeToZero' xs = [if (-x) `Set.member` unwanted then 0 else x | x <- xs]
  where unwanted = Set.fromList $ filter (< 0) xs

你實際上不記得你在列表中找到了哪些負面符號

import qualified Data.Set as S

changeToZero :: [Int] -> [Int]
changeToZero [] = []
changeToZero xs = reverse . snd $ foldl f (S.empty,[]) xs
  where
    f (negs,res) x | x < 0 = (S.insert (-x) negs, x:res)
                   | S.member x negs = (negs,0:res)
                   | otherwise = (negs,x:res)

好吧,基於@jdevelop 的答案,如果負數必須出現在正數之前才能計數,那么您可以通過輸入一次構建結果,而無需反轉它:

import qualified Data.Set as S
import Control.Monad.State

changeToZero :: [Int] -> [Int]
changeToZero xs = evalState (mapM f xs) S.empty where
  f x | x < 0     = modify (S.insert (-x)) >> return x
      | otherwise = gets (S.member x) >>= \hasNeg -> return $ if hasNeg then 0 else x

通過這種方式,您可以得到答案

take 4 $ changeToZero $ 1 : (-2) : 3 : 2 : undefined

其他解決方案將失敗的地方。

** 編輯 **

這是同樣的事情,但沒有State monad,這使得它更容易理解:

changeToZero' :: [Int] -> [Int]
changeToZero' = go S.empty where
  go _ [] = []
  go s (x:xs) | x < 0        = x : go (S.insert (-x) s) xs
              | S.member x s = 0 : go s xs
              | otherwise    = x : go s xs

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM