Спрашивали тут, зачем нужен (<*>)
Nov. 10th, 2011 07:20 pmВ Haskell нельзя перегрузить функцию с одним именем, но разным числом аргументов (например, потому что вывод типов спасует при частичном применении). Поэтому мы были вынуждены в некоторых ситуациях генерировать семейства практически идентичных функций, например zipWith_n
*Test> let x1s = [1,2,3] *Test> let x2s = [4,5,6] *Test> let x3s = [7,8,9] *Test> let x4s = [10,11,12] *Test> zipWith (\a b -> 2*a+3*b) x1s x2s [14,19,24] *Test> zipWith3 (\a b c -> 2*a+3*b+5*c) x1s x2s x3s [49,59,69] *Test> zipWith4 (\a b c d -> 2*a+3*b+5*c-4*d) x1s x2s x3s x4s [9,15,21]Аппликативные функторы позволяют решить эту проблему
*Test> getZipList $ (\a b -> 2*a+3*b) <$> ZipList x1s <*> ZipList x2s [14,19,24] *Test> getZipList $ (\a b c -> 2*a+3*b+5*c) <$> ZipList x1s <*> ZipList x2s <*> ZipList x3s [49,59,69] *Test> getZipList $ (\a b c d -> 2*a+3*b+5*c-4*d) <$> ZipList x1s <*> ZipList x2s <*> ZipList x3s <*> ZipList x4s [9,15,21]Это, конечно, выглядит кошмарно. Однако упаковка/разупаковка getZipList / ZipList тут нужна, поскольку главным инстансом аппликативного функтора для списков был выбран не зипующий (<<номер в номер>>), а <<каждый с каждым>>. Если нам часто нужно делать такие многоаргументные зипы, то можно определить операторы - аналоги (<*>) и (<$>), но с дополнительной ZipList / getZipList нагрузкой:
infixl 4 >*<, >$< (>*<) :: [a -> b] -> [a] -> [b] fs >*< xs = getZipList $ ZipList fs <*> ZipList xs (>$<) :: (a -> b) -> [a] -> [b] f >$< xs = getZipList $ f <$> ZipList xsПосле этого всё выглядит вполне компактно и не требует лишних имён для зипов:
*Test> (\a b -> 2*a+3*b) >$< x1s >*< x2s [14,19,24] *Test> (\a b c -> 2*a+3*b+5*c) >$< x1s >*< x2s >*< x3s [49,59,69] *Test> (\a b c d -> 2*a+3*b+5*c-4*d) >$< x1s >*< x2s >*< x3s >*< x4s [9,15,21]