Estou aprendendo OCaml e estou tendo um pouco de dificuldade com programação funcional...
Preciso fazer uma função que substitua a para uma lista dada de inteiros, os caracteres naquele índice de uma string. Digamos, por exemplo, que eu receba [1;4] 'u' "Hello" como entrada, ele retorna "Hullu".
Isto é o que eu criei:
let remplace_positions lst c str =
let rec acc lst c str n l_index ret =
match (n >= String.length str, List.nth lst l_index = n) with
| true, _ -> ret
| _, true -> acc lst c (n+1) (l_index+1) (ret ^ (String.make 1 c))
| _, _ -> acc lst c (n+1) (l_index+1) (ret ^ (String.make 1 (String.get str n)))
in
acc lst c str 0 0 ""
Mas como você pode ver, há um erro nos dois últimos casos de correspondência. Eles são do tipo string -> string, mas eu quero que eles sejam do tipo string.
Alguém sabe como consertar isso ao chamar a função recursivamente?
Quando testo sua função, obtenho:
Referindo-se ao
(n+1)
in line:Isso ocorre porque você indicou que o terceiro argumento
acc
deveria ser umstring
, mas depois você passa umint
.Eu sugeriria que você está passando argumentos demais para
acc
de qualquer forma, dificultando o controle deles. Se eles não mudarem, não há necessidade de que a função interna os tome como argumentos. A função interna será capaz de acessar ligações do escopo externo, desde que não sejam sombreadas.Também podemos fatorar a transformação de um caractere em uma string.
Mesmo erro, mas código um pouco mais fácil de ler.
Agora, vamos remover a passagem desnecessária do
str
argumento:Agora ele compila. Então vamos executá-lo.
Onde é que isto deu errado?
Bem, vamos traçar isso:
Você incrementou o índice da sua lista a ponto de ele tentar acessar a lista fora dos limites, resultando em uma exceção.
Para ser honesto, sua abordagem básica não vale a pena salvar. Usar
List.nth
even com sucesso é ineficiente porque é uma operação O(n) em vez de O(1).O que você precisa fazer, em última análise, é iterar sobre a lista e substituir os caracteres em cada um dos índices pelo seu caractere especificado. A correspondência de padrões em listas fornece a maneira mais idiomática de realizar essa iteração sobre a lista.
Mas ter strings imutáveis em OCaml torna isso confuso. Tudo isso de obter substrings e concatená-las de volta realmente ocupa muito espaço. Seria mais fácil se elas fossem mutáveis.
Felizmente é para isso que o
Bytes
módulo serve. Podemos converter para umbytes
tipo mutável, modificá-lo e então converter de volta para umstring
.Mas, na verdade, iterar sobre uma lista e aplicar uma operação a cada elemento já é algo que é feito por
List.iter
.