Есть ли способ без шаблонов преобразовать HLists в список аргументов?

В соответствии с этим вопросом Spray использует sbt-boilerplate для создания ApplyConverter экземпляров, которые неявно преобразуют A :: B :: ... :: HNil => R в более традиционный (A, B, ...) => R для простоты использования. . Этот вопрос был задан более года назад; можно ли теперь это сделать, используя, например, макросы или новую функциональность Shapeless, чтобы не требовался этап генерации внешнего кода?


person Jonathan Chow    schedule 19.11.2014    source источник
comment
ИМО шаблон должен быть частью бесформенного. Я однажды задал аналогичный вопрос в рассылке, но не т следить. Так что, если вам нужна эта функциональность, возможно, имеет смысл спросить еще раз.   -  person jrudolph    schedule 20.11.2014
comment
Я в замешательстве... это было бесформенной частью почти с самого начала... что я упускаю?   -  person Miles Sabin    schedule 20.11.2014
comment
@MilesSabin Во-первых, позвольте мне сказать спасибо за форму и всю работу, которую вы вложили в нее, я думаю, что это потрясающая библиотека для Scala! Но я хотел знать, возможно ли это без внешней генерации кода, под которой я неточно имел в виду, как способ, который делает некоторую магию на уровне типов, чтобы вы могли каким-то образом рекурсивно вводить аргументы в функцию или что-то еще, или по-другому использовать метод это не зависит от отдельного экземпляра для каждого FunctionN. Насколько я могу судить, shapeless по-прежнему генерирует свои экземпляры FnFromProduct, используя шаблон.   -  person Jonathan Chow    schedule 21.11.2014
comment
Я думаю, это зависит от того, что вы подразумеваете под внешней генерацией кода. Как пользователь shapeless вам не придется прибегать к какой-либо форме генерации кода. Генерация кода используется внутренне для бесформенного, конечно, отражая генерацию кода в стандартной библиотеке Scala и компиляторе ... учитывая то, как в настоящее время определяются типы функций Scala (т.е. как совершенно не связанные), это неизбежно. Разумным выходом из этого было бы для гипотетического варианта Scala использовать каррированные типы функций в качестве основных ... как бы желательно это ни было, я не вижу, чтобы это произошло в ближайшее время.   -  person Miles Sabin    schedule 21.11.2014
comment
Итак, я задаю два разных вопроса: во-первых, возможно ли это с shapeless, и ответ — да, но во-вторых, возможно ли это в vanilla Scala без дублирования кода, и ответ — нет. Я думаю, что ответ Майлза более прямо отвечает на мой вопрос, поэтому я отмечу это как ответ, однако я также не думаю, что ответ Лмм неверен.   -  person Jonathan Chow    schedule 21.11.2014


Ответы (2)


Это было включено в бесформенное в течение очень долгого времени. В shapeless 2.0.0 вы можете сделать следующее:

scala> import shapeless._, syntax.std.function._
import shapeless._
import syntax.std.function._

scala> val f1: (Int, String, Boolean) => Int = (i, s, b) => i+s.length+(if(b) 1 else 0)
f1: (Int, String, Boolean) => Int = <function3>

scala> val pf1 = f1.toProduct
pf1: Int :: String :: Boolean :: HNil => Int = <function1>

scala> pf1(23 :: "foo" :: true :: HNil)
res0: Int = 27

scala> val pf2: (Int :: String :: HNil) => Int = l => l.head+l.tail.head.length
pf2: Int :: String :: HNil => Int = <function1>

scala> val f2 = pf2.fromProduct
f2: (Int, String) => Int = <function2>

scala> f2(23, "foo")
res1: Int = 26

(Отображение типа результата REPL приведено в порядок для удобочитаемости).

person Miles Sabin    schedule 20.11.2014

Я думаю, что в чистом Scala это сделать невозможно, так как нет возможности в общем говорить об интерфейсах FunctionN. На макроуровне это было бы возможно, но не так, чтобы можно было использовать представление AST; макрос для этого, вероятно, будет сведен к (эффективному) выполнению манипуляций со строками - в этом случае очень мало преимуществ перед sbt-boilerplate.

Даже если бы это стало возможным, Spray — довольно фундаментальная библиотека, которую необходимо использовать в сочетании с другими библиотеками (таким образом, она продолжает создавать выпуски для старых версий Scala и Akka) — что-то, что станет более важным только тогда, когда Play портирован для работы поверх Spray. Так что я ожидаю, что пройдет какое-то время, прежде чем Spray введет жесткую зависимость от Shapeless 2 (которая несовместима с Shapeless 1), и до тех пор, я думаю, они попытаются сохранить код для shapeless2 сборки spray-routing как можно ближе. насколько это возможно для бесформенной1 сборки для простоты обслуживания.

person lmm    schedule 19.11.2014
comment
К вашему сведению: на самом деле, спрей, вероятно, больше не получит таких больших обновлений. Вместо этого новые усилия по разработке будут в основном касаться akka-http. В маршрутной части akka-http зависимость от shapeless2 была полностью удалена, а DSL теперь основан на кортежах Scala, а не на списках HL. Тем не менее, проблема остается точно такой же, и шаблон должен генерироваться, как и раньше. - person jrudolph; 20.11.2014
comment
Кстати. Почему бы это не сработать: на макроуровне это было бы возможно, но не таким образом, чтобы использовать доступное представление AST. На макроуровне у вас есть доступ ко всем типам, поэтому вы можете выполнять любые расчеты типа y, которые хотите. - person jrudolph; 20.11.2014
comment
Это ужасно, надеюсь, они передумают. HLists намного лучше, чем кортежи Scala, и у меня есть рабочий код Spray, который зависит от этой разницы. Что касается вашего вопроса, макроуровень имеет доступ к типам, но ничего не знает об отношениях между различными интерфейсами FunctionN. Таким образом, макрос должен будет использовать манипуляции со строками, чтобы получить правильный FunctionN. Дело не в том, что макрос не может этого сделать, а в том, что макрос не может сделать это лучше, чем текстовый процессор. - person lmm; 20.11.2014
comment
Я не думаю, что вам нужно работать с FunctionN интерфейсами в макросе. Есть элемент AST для анонимной функции, где вам просто нужно передать нужное количество параметров. Тем не менее, я думаю, что понимаю, о чем вы говорите: на каком-то уровне вам нужно сделать какой-то тупой перевод (и лучше сделать это прямо в компиляторе). - person jrudolph; 20.11.2014
comment
Что касается изменения кортежей: я не думаю, что это так плохо, как вы думаете. То, что мы сделали (на самом деле, я внес изменение), — это удаление жесткой зависимости от shapeless, что само по себе в первую очередь хорошо (на одну зависимость меньше, с которой вы можете столкнуться с конфликтами). Это не означает, что HLists больше не будут поддерживаться. Идея состоит в том, что появится необязательный соединительный модуль, предоставляющий достаточно помощников для повторного включения шаблонов, которые ранее были возможны при прямой поддержке HList. Это работает, потому что для shapeless не имеет значения, работаете ли вы с HList, кортежами или case-классами. - person jrudolph; 20.11.2014
comment
Я только что создал тикет в akka, чтобы мы не забыли об этом дополнительном модуле: github.com /акка/акка/вопросы/16343. Я приглашаю вас добавить комментарий о том, как вы используете спрей в сочетании с бесформенным, что не будет работать, как с новым подходом, основанным на кортежах. Это было бы очень полезно! Спасибо за обсуждение здесь в любом случае :) - person jrudolph; 20.11.2014
comment
Спасибо за комментарии! Мне как-то удалось забыть, что заставило меня задать этот вопрос в первую очередь, но я сел и попытался реализовать функцию для преобразования HList в список аргументов в любом случае и столкнулся с тем, что описывает @lmm: HLists позволяют вам абстрагироваться от арности значений, но в Scala нет способа абстрагироваться от арности функции. Ну что ж. По крайней мере, теперь я лучше понимаю ограничения Scala :) - person Jonathan Chow; 20.11.2014