۲۰ - ۸همه‌های کارها رو انجام بده

اینجا از یه کتابخونه ِ کلاینت ِ HTTP به اسم ‏‎wreq‎‏ استفاده می‌کنیم تا به یه وب‌سایتِ به‌دردبخور برای تست ِ کلاینت‌های HTTP به آدرسِ ‏‎http://httpbin.org/‎‏ درخواست بدیم. هر آزمایشی دوست داشتین باهاش انجام بدین؛ اگر هم ایده‌ای داشتین، کُد رو تغییر بدین:

module HttpStuff where

import Data.ByteString.Lazy hiding (map)
import Network.Wreq

-- ،اگه دوست یا لازم داشتین
-- .آدرس وب‌سایت رو عوض کنین
urls :: [String]
urls = [ "http://httpbin.org/ip"
       , "http://httpbin.org/bytes/5"
       ]

mappingGet :: [IO (Response ByteString)]
mappingGet = map get urls

ولی اگه بجای یه لیست از اجراییه‌های ‏‎IO‎‏ که اجرای هرکدوم یه پاسخ میده، یه اجراییه ِ ‏‎IO‎‏ ِ بزرگ بخوایم که یه لیست از پاسخ‌ها درست می‌کنه چطور؟ اینجا میشه از ‏‎Traversable‎‏ استفاده کرد:

traversedUrls :: IO [Response ByteString]
traversedUrls = traverse get urls

امیدواریم با این مثال‌ها متوجهِ مفید بودنِ تایپکلاسِ ‏‎Traversable‎‏ شده باشین. با اینکه ‏‎Foldable‎‏ به نظر پیش‌وپاافتاده میاد، اما یه سوپرکلاس ِ واجب برای ‏‎Traversable‎‏ ِه، و امروزه دیگه ‏‎Traversable‎‏ هم، مثل ‏‎Functor‎‏ و ‏‎Monad‎‏، به خاطرِ کاربردی بودنش در هسکل‌نویسیِ روزمره استفاده میشه.

درکِ قدرتِ بیشتر

‏‎Traversable‎‏ از ‏‎Functor‎‏ و ‏‎Foldable‎‏ قوی‌تره، به همین خاطر میشه از ‏‎Traversable‎‏ به ‏‎Functor‎‏ و ‏‎Foldable‎‏ رسید، همونطور که میشه از ‏‎Monad‎‏ به ‏‎Functor‎‏ و ‏‎Applicative‎‏ رسید. در مثالِ زیر با استفاده از تایپِ ‏‎Identity‎‏، تابعِ ‏‎fmap‎‏ رو بازسازی کردیم:

λ> import Data.Functor.Identity
λ> traverse (Identity . (+1)) [1, 2]
Identity [2,3]
λ> runIdentity $ traverse (Identity . (+1)) [1, 2]
[2,3]
λ> :{
λ| let edgeMap f t = runIdentity $
λ|       traverse (Identity . f) t
λ| :}
λ> :t edgeMap
edgeMap :: Traversable t => (a -> b) -> t a -> t b
λ> edgeMap (+1) [1..5]
[2,3,4,5,6]

با استفاده از ‏‎Const‎‏ یا ‏‎Constant‎‏ هم میشه یه تابعی شبیهِ ‏‎foldMap‎‏ از ‏‎Foldable‎‏ رو بدست آورد:

λ> import Data.Monoid
-- `transformers` از
λ> mport Data.Functor.Constant

λ> let xs = [1, 2, 3, 4, 5] :: [Sum Integer]
λ> traverse (Constant . (+1)) xs
Constant (Sum {getSum = 20})

λ> :{
λ| let foldMap' f t =
λ|      getConstant $ traverse (Constant . f) t
λ| :}
λ> :t foldMap'
foldMap' :: (Traversable t, Monoid a)
         => (a1 -> a) -> t a1 -> a
λ> :t foldMap
foldMap  :: (Foldable t, Monoid m)
         => (a  -> m) -> t  a -> m

با انجامِ چنین تمرین‌هایی درک‌تون از رابطه‌ی بین این تایپکلاس‌ها و تابع‌های کانونیک‌ِشون بیشتر میشه. قبول داریم که اینها ممکنه به نظر بیشتر از تمرین نباشن، اما نهایتاً چنین تسلطی در بازی با توابع‌ه که آدم رو به هسکل مسلط می‌کنه.