Бессмысленный стиль и использование $ - PullRequest
10 голосов
/ 16 ноября 2011

Как объединить, используя $ и стиль без очков?

Ярким примером является следующая служебная функция:

times :: Int -> [a] -> [a]
times n xs = concat $ replicate n xs  

Просто запись concat $ replicate приводит к ошибке, также вы не можете написать concat . replicate, потому что concat ожидает значение, а не функцию.

Так как бы вы превратили вышеуказанную функцию в стиль без точек?

Ответы [ 5 ]

22 голосов
/ 16 ноября 2011

Вы можете использовать этот комбинатор: (двоеточие подсказывает, что следуют два аргумента)

(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.) . (.)

Позволяет избавиться от n:

time = concat .: replicate
13 голосов
/ 16 ноября 2011

Вы можете легко написать почти бессмысленную версию с помощью

times n  =  concat . replicate n

Полностью бессмысленная версия может быть получена с явным карри и uncurry:

times  =  curry $ concat . uncurry replicate
12 голосов
/ 16 ноября 2011

Получить на freenode и спросить lambdabot;)

<jleedev> @pl \n xs -> concat $ replicate n xs
<lambdabot> (join .) . replicate
1 голос
/ 26 февраля 2015

Расширяя ответ FUZxxl, мы получили

(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.).(.)

(.::) :: (d -> e) -> (a -> b -> c -> d) -> a -> b -> c -> e
(.::) = (.).(.:)

(.:::) :: (e -> f) -> (a -> b -> c -> d -> e) -> a -> b -> c -> d -> f
(.:::) = (.).(.::)

...

Очень приятно.

Бонус

(.:::) :: (e -> f) -> (a -> b -> c -> d -> e) -> a -> b -> c -> d -> f
(.:::) = (.:).(.:)

Эмм ... так что, может быть, мы должны сказать

(.1) = .

(.2) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.2) = (.1).(.1)

(.3) :: (d -> e) -> (a -> b -> c -> d) -> a -> b -> c -> e
(.3) = (.1).(.2)
-- alternatively, (.3) = (.2).(.1)

(.4) :: (e -> f) -> (a -> b -> c -> d -> e) -> a -> b -> c -> d -> f
(.4) = (.1).(.3)
-- alternative 1 -- (.4) = (.2).(.2)
-- alternative 2 -- (.4) = (.3).(.1)

Еще лучше.

Мыможно также расширить это значение до

fmap2 :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
fmap2 f = fmap (fmap f)

fmap4 :: (Functor f, Functor g, Functor h, functro i) 
   => (a -> b) -> f (g (h (i a))) -> f (g (h (i b)))
fmap4 f = fmap2 (fmap2 f)

, которое следует той же схеме.

Было бы еще лучше иметь параметризованные времена применения fmap или (.).Однако эти fmap или (.) s на самом деле различаются по типу.Таким образом, единственный способ сделать это - использовать расчет времени компиляции, например TemplateHaskell.

. Для повседневного использования я бы просто предложил

Prelude> ((.).(.)) concat replicate 5 [1,2]
[1,2,1,2,1,2,1,2,1,2]
Prelude> ((.).(.).(.)) (*10) foldr (+) 3 [2,1]
60
1 голос
/ 26 февраля 2015

В Haskell композиция функций ассоциативна¹:

f . g . h == (f . g) . h == f . (g . h)

Любой инфиксный оператор - это просто хорошая старая функция:

2 + 3 == (+) 2 3
f 2 3 = 2 `f` 3

A оператор композиции тоже просто двоичная функция, высшего порядка , она принимает 2 функции и возвращает функцию:

(.) :: (b -> c) -> (a -> b) -> (a -> c)

Поэтому любой оператор композиции может быть переписан так:

f . g == (.) f g
f . g . h == (f . g) . h == ((.) f g) . h == (.) ((.) f g) h
f . g . h == f . (g . h) == f . ((.) g h) == (.) f ((.) g h)

Каждая функция в Haskell может быть частично применена из-за curry по умолчанию. Инфиксные операторы могут быть частично применены очень кратким способом, используя секции :

(-) == (\x y -> x - y)
(2-) == (-) 2 == (\y -> 2 - y)
(-2) == flip (-) 2 == (\x -> (-) x 2) == (\x -> x - 2)
(2-) 3 == -1
(-2) 3 == 1

Так как оператор композиции - это обычная бинарная функция, вы также можете использовать ее в секциях:

f . g == (.) f g == (f.) g == (.g) f

Еще один интересный бинарный оператор - $ , который является просто приложением функции:

f x == f $ x
f x y z == (((f x) y) z) == f x y z
f(g(h x)) == f $ g $ h $ x == f . g . h $ x == (f . g . h) x

С этим знанием, как мне преобразовать concat $ replicate n xs в стиль без очков?

times n xs = concat $ replicate n xs
times n xs = concat $ (replicate n) xs
times n xs = concat $ replicate n $ xs
times n xs = concat . replicate n $ xs
times n    = concat . replicate n
times n    = (.) concat (replicate n)
times n    = (concat.) (replicate n) -- concat is 1st arg to (.)
times n    = (concat.) $ replicate n
times n    = (concat.) . replicate $ n
times      = (concat.) . replicate

¹ Haskell основан на теории категорий . Категория в теории категорий состоит из 3 вещей: некоторые объекты , некоторые морфизмы и понятие композиции морфизмов. Каждый морфизм соединяет исходный объект с целевым объектом , в одну сторону. Теория категорий требует, чтобы композиция морфизмов была ассоциативной. Категория, которая используется в Haskell, называется Hask , чьи объекты являются типами, а морфизмы - функциями. Функция f :: Int -> String - это морфизм, который связывает объект Int с объектом String. Поэтому теория категорий требует, чтобы композиции функций Хаскелла были ассоциативными.

...