Haskell: Как мне составить функции «назад», как поток Clojure (->)? - PullRequest
1 голос
/ 27 февраля 2020

новый для Haskell здесь.

Я хотел бы написать:

take 1 $ take 2 [1, 2, 3] -- = 1

обратный , как этот псевдокод:

[1, 2, 3] -> take 2 -> take 1 -- = 1

В Clojure мы можем сделать это с помощью:

(->> [1 2 3]
  (take 2)
  (take 1)) ;=> (1)

Clojure делает это, потому что ->> - это макрос, который переписывает выражение в (take 1 (take 2 [1 2 3])), а потому что Haskell является ленивым и имеет частичные и еще, кажется, это должно быть легко.

Я хочу сделать это, потому что сначала иметь данные, а затем читать функции, чтобы они выполнялись, это прекрасный способ чтения кода. Я был избалован Clojure!

Это похоже на беглый интерфейс / цепочку var.action1().action2() et c в объектно-ориентированных языках.

Я думаю, это возможно в Template Haskell, но наверняка есть встроенный способ сделать это, которого я еще не знаю? Спасибо!

Ответы [ 2 ]

11 голосов
/ 27 февраля 2020

Существует (&), который необходимо импортировать из Data.Function.

> import Data.Function
> [1,2,3] & take 2 & take 1
[1]

Если вы действительно не хотите импортировать этот модуль, определение просто (&) = flip ($).

4 голосов
/ 27 февраля 2020

Ответ Чепнера полностью правильный.

Есть и другие способы злоупотребления синтаксисом Haskell, но код ниже не следует использовать для каких-либо серьезных приложений.

RebindableSyntax нарушает ожидания пользователей относительно значения стандартных конструкций. Функции Variadi c имеют ужасный вывод типов, сообщения об ошибках и критические случаи (эти проблемы могут быть устранены с неоправданным усилием, но никогда не будут полностью решены). нотация do {x ; y} является сахаром для x >> y, а расширение RebindableSyntax позволяет перепривязать (>>). Вы можете переопределить его как (обращенную) композицию функций, например:

y :: [Int]
y = [1,2,3] & do
  take 2
  take 1
 where
  (>>) = flip (.)

Variadics

Вы можете использовать классы типов, чтобы определить (->>) как функцию variadi c.

z :: [Int]
z = (->>) [1,2,3]
  (take 2)
  (take 1)

class App a b where
  (->>) :: a -> b

instance (a ~ a', App b c) => App a ((a' -> b) -> c) where
  (->>) x y = (->>) (y x)

instance {-# OVERLAPPABLE #-} (a ~ a') => App a a' where
  (->>) = id

Полный смысл: https://gist.github.com/Lysxia/3461f489cc5057ea089e23a4eede375a

...