Tôi có một danh sách các bản ghi và cần chức năng tìm kiếm danh sách bản ghi với tên đã cho và sửa đổi giá trị của hồ sơ này HOẶC nếu không có bản ghi khớp nối thêm một bản ghi mới vào danh sách kết quả. Đây là mã của tôi cho đến nay:Thay đổi phần tử của danh sách nếu nó giữ lại một số điều kiện hoặc thêm một phần mới nếu không, sử dụng Data.Lens
import Control.Lens
import Control.Applicative ((<$>), pure)
import Data.List (any)
data SomeRec = SomeRec { _name :: String, _val :: Int }
$(makeLenses ''SomeRec)
_find :: (a -> Bool) -> Simple Traversal [a] a
_find _ _ [] = pure []
_find pred f (a:as) = if pred a
then (: as) <$> f a
else (a:) <$> (_find pred f as)
changeOrCreate :: [SomeRec] -> String -> (Int -> Int) -> [SomeRec]
changeOrCreate recs nameToSearch valModifier =
if (any (\r -> r^.name == nameToSearch) recs)
then over (_find (\r -> r^.name == nameToSearch)) (over val valModifier) recs
else recs ++ [SomeRec nameToSearch (valModifier 0)]
Nó hoạt động tốt, nhưng tôi đang tự hỏi nếu có một cách trực tiếp hơn của văn bản này sử dụng Data.Lens
(không có if
-construct)? Ngoài ra, tôi có phải viết hàm _find
hoặc có điều gì đó tương đương trong thư viện không?
Cập nhật: Đây là một Gist của nguồn để thử nghiệm: https://gist.github.com/SKoschnicke/5795863
Vì vậy, một 'Prism' cho phép tôi thay đổi danh sách? Tôi nghĩ rằng tôi phải kiểm tra để hiểu hoàn toàn, sẽ làm điều đó vào ngày mai! –
Hoạt động độc đáo! Nhưng theo như tôi hiểu, với việc sử dụng 'lọc',' pos' không còn là 'Traversal' hợp lệ nữa, đúng không? Do đó, nó thường không tương thích với các traversals khác. –
Đó thực sự không phải là 'Traversal' hợp lệ nếu bạn sử dụng nó để thay đổi trường' name' và do đó làm cho vị từ không giữ nữa ("quy tắc" có thể bị vỡ, như được minh họa trong câu trả lời của Matvey), nhưng ngược lại, nó có thể phối hợp với traversals. – yairchu