2012-06-07 7 views
9

Я пытался преобразовать пример haskell, который я натолкнул раньше, на scalaz. Оригинальный пример был такой:Аппликационный экземпляр для кортежа с моноидом и функцией внутри

("Answer to the ", (*)) <*> ("Ultimate Question of ", 6) <*> ("Life, the Universe, and Everything", 7) 

Который, насколько я могу понять, использует this экземпляр.

Это не преобразуются в scalaz буквально:

scala> ("Answer to the ", ((_: Int) * (_: Int)) curried) |@| ("Ultimate Question of ", 6) |@| ("Life, the Universe, and Everything", 7) tupled 
res37: (java.lang.String, (Int => (Int => Int), Int, Int)) = (Answer to the Ultimate Question of Life, the Universe, and Everything,(<function1>,6,7)) 

Хотя, я искал экземпляр, и это, кажется be there (опять же, насколько я могу понять).

Итак, вопрос в том, почему он не работает так? Или что я пропустил/не понял?

+1

Этот код действительно отправляет в аппликативный экземпляр для кортежей. Это, в свою очередь, использует моноидный 'mappend' для списков (concatentation). Таким образом, это функциональный состав 2-го компонента кортежа со списком совпадений первой части. –

ответ

5

Экземпляр Scalaz's Control.Applicative<*> также называется <*>, хотя он смущенно принимает свои аргументы в обратном порядке. Так что следующие работы:

val times = ((_: Int) * (_: Int)) curried 
val a = "Answer to the " 
val b = "Ultimate Question of " 
val c = "Life, the Universe, and Everything" 

(c, 7) <*> ((b, 6) <*> (a, times)) 

Или, как я уже отметил, в ответ на ваш комментарий, вы можете использовать следующее, если вы хотите придерживаться |@|:

(a -> times |@| b -> 6 |@| c -> 7)(_ apply _ apply _) 

Я лично предпочитаю <*> версии, даже если он чувствует себя в обратном направлении.


Мы можем пройти через то, что происходит в деталях. Прежде всего, вам не нужна полная мощность Applicative здесь. Apply будет делать. Мы можем получить Apply экземпляр для кортежей с помощью implicitly:

scala> val ai = implicitly[Apply[({type λ[α]=(String, α)})#λ]] 
ai: scalaz.Apply[[α](java.lang.String, α)] = [email protected] 

Теперь мы можем применить наш первый кортеж на второй:

scala> :t ai(a -> times, b -> 6) 
(java.lang.String, Int => Int) 

И результат на третий:

scala> :t ai(ai(a -> times, b -> 6), c -> 7) 
(java.lang.String, Int) 

Это то, что мы хотим:

scala> ai(ai(a -> times, b -> 6), c -> 7)._1 
res0: java.lang.String = Answer to the Ultimate Question of Life, the Universe, and Everything 

scala> ai(ai(a -> times, b -> 6), c -> 7)._2 
res1: Int = 42 

Метод <*> на MA просто обертывает это немного более красиво.

+0

Спасибо, работает, как предполагается. Кстати, есть ли у вас какие-либо идеи, как это сделать с ApplicativeBuilder, и если это будет выглядеть лучше? – folone

+1

Конечно, вы могли бы сделать что-то вроде '(a -> times | @ | b -> 6 | @ | c -> 7) (_ apply _ apply _)', но я думаю, что версия '<*>' лучше. –

+0

Да, это работает. Я был введен в заблуждение тем фактом, что 'tupled' склеил моноид, так что я думал, что это применит и функцию. – folone