Aplicar uma lista de argumentos à função ao curry usando foldLeft no Scala
É possível fazer umfoldLeft
em uma lista de argumentos, onde o valor inicial fornecido para a dobra é uma função totalmente curry, o operador éapply
e a lista é uma lista de argumentos a serem passados para a funçãof
?
Por exemplo, digamos que f é definido como:
scala> val f = (i: Int, j: Int, k: Int, l: Int) => i+j+k+l
f: (Int, Int, Int, Int) => Int = <function4>
Qual é claro que podemos usar diretamente:
scala> f(1, 2, 3, 4)
res1: Int = 10
O curry e aplique os argumentos um de cada vez:
scala> f.curried
res2: Int => Int => Int => Int => Int = <function1>
scala> f.curried.apply(1).apply(2).apply(3).apply(4)
res3: Int = 10
À primeira vista, isso parece um trabalho parafoldLeft
.
Minha primeira tentativa de descrever esta sequência deapply
usandofoldLeft
parece
scala> List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })
No entanto, isso gera o seguinte erro:
<console>:9: error: type mismatch;
found : Int => Int => Int => Int
required: Int => Int => Int => Int => Int
List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })
Minha leitura da mensagem de erro é que a inferência de tipo precisaria de alguma dica parag
.
A solução que estou procurando deixa tudo não modificado na minha expressão original, exceto o tipo deg
:
List(1, 2, 3, 4).foldLeft(f.curried)({ (g: ANSWER, x) => g.apply(x) })
Meu primeiro pensamento foi que um tipo de união seria útil aqui. Eu já vi a derivação de tipos de união de Miles Sabin usando Curry-Howard; portanto, se esse primeiro palpite é verdadeiro, parece que tenho o mecanismo básico necessário para resolver o problem
No entanto: Mesmo que os tipos de união sejam a resposta, seria útil se eu pudesse me referir a "A união de todos os tipos, desde o tipo de função totalmente com curry ao tipo de função com curry, com exceção do último argumento fornecido". Em outras palavras, uma maneira de transformar o tipo:
T1 => ... => Tn
no tipo de união:
(T1 => ... => Tn) |∨| ... |∨| (Tn-1 => Tn)
seria útil como o tipo parag
acima
Fazer umfoldLeft
com umList
limita a discussão ao caso em queT1
atravésTn-1
são todos iguais. Uma notação como
(T1 =>)+ Tn
descreveria o tipo que eu quero fornecerg
.
O caso específico sobre o qual estou perguntando não exige cadeias arbitrariamente longas, para que possamos fornecer limites ao iterador usando
(T1 =>){1,4} Tn
Esperando ansiosamente fazer isso por cadeias de tipos que não são iguais, talvez seja útil alguma função mágica em tipos que agrupam a cadeia no conjunto de todos os sufixos:
Suffixes(T1 => ... => Tn)
Implementar isso está muito além das minhas habilidades no Scala no momento. Qualquer sugestão sobre como fazê-lo seria apreciada. Se isso pode ser feito com o uso avançado do sistema de tipos existente do Scala ou por meio de um plug-in de compilador ou não, eu não se
As foi observado nos comentários abaixo, chamar o resultado de "tipo de união" não é o ajuste perfeito para este caso de uso. Não sei mais o que chamar, mas essa é a ideia mais próxima que tenho no momento. Outros idiomas têm suporte especial para essa ideia? Como isso funcionaria na Coq e na Agda?
Nomear esse problema e entender onde ele se encontra em relação à visão geral (da teoria dos tipos, da decidibilidade etc.) é mais importante para mim do que ter uma implementação funcional deANSWER
, embora ambos sejam legais. O bônus aponta para qualquer pessoa que possa estabelecer conexões com Scalaz, Monoids ou Teoria da Categoria em gera