Esercizio in Haskell
Salve a tutti,
recentemente, studiando per un esame, mi sono imbattuto nel seguente esercizio in Haskell:
Un numero naturale n si dice perfetto se la somma dei suoi divisori (incluso n) è pari a 2n.
Escluso lo 0 (che non è perfetto per convenzione) i primi tre numeri perfetti sono 6, 28 e
496. Senza usare list comprehension o funzioni della libreria standard, definire una funzione
che, applicata a n, determina se n è perfetto.
ovviamente la limitazione circa l' uso di funzioni della libreria standard non comprende +,- o altre funzioni con nome simbolico.
Quello che non capisco è: esiste un modo per iterare su una lista senza usare head, tail o list comprehension? Ho provato con l' operatore !!, tuttavia non vi è modo(che io sappia) di determinare se l' elemento al quale si tenta di accedere esista, a meno che non si compari l'indice con length che, tuttavia, è comunque una funzione della libreria standard.
Saluti.
recentemente, studiando per un esame, mi sono imbattuto nel seguente esercizio in Haskell:
Un numero naturale n si dice perfetto se la somma dei suoi divisori (incluso n) è pari a 2n.
Escluso lo 0 (che non è perfetto per convenzione) i primi tre numeri perfetti sono 6, 28 e
496. Senza usare list comprehension o funzioni della libreria standard, definire una funzione
perfetto:: Int => Bool
che, applicata a n, determina se n è perfetto.
ovviamente la limitazione circa l' uso di funzioni della libreria standard non comprende +,- o altre funzioni con nome simbolico.
Quello che non capisco è: esiste un modo per iterare su una lista senza usare head, tail o list comprehension? Ho provato con l' operatore !!, tuttavia non vi è modo(che io sappia) di determinare se l' elemento al quale si tenta di accedere esista, a meno che non si compari l'indice con length che, tuttavia, è comunque una funzione della libreria standard.
Saluti.
Risposte
Puoi semplicemente usare la ricorsione. Per esempio, per sommare tutti i divisori di un numero:
Il codice assume gli venga passato un numero positivo e va in loop infinito altrimenti (dovresti forse modificarlo in modo che funzioni correttamente..). Ma spero che l'idea sia chiara.
sommaDivisori n = sommaDivisori' n n 0 sommaDivisori' _ 0 s = s sommaDivisori' n i s = sommaDivisori' n (i-1) s' where s' = if n `mod` i == 0 then s + i else s
Il codice assume gli venga passato un numero positivo e va in loop infinito altrimenti (dovresti forse modificarlo in modo che funzioni correttamente..). Ma spero che l'idea sia chiara.
"Michele/96":
Quello che non capisco è: esiste un modo per iterare su una lista senza usare head, tail o list comprehension? Ho provato con l' operatore !!, tuttavia non vi è modo(che io sappia) di determinare se l' elemento al quale si tenta di accedere esista, a meno che non si compari l'indice con length che, tuttavia, è comunque una funzione della libreria standard.
Pattern matching e ricorsione?
f :: [a] -> Int f (x:xs) = 1 + f xs -- La lista ha almeno un elemento f [] = 0 -- La lista è vuota
O anche pattern guards
f :: [a] -> Int f (x:xs) | x == 0 = 1 + f xs -- La lista ha almeno un elemento, che è uguale a zero | x > 0 = 1 + f xs -- La lista ha almeno un elemento, che è maggiore di zero | otherwise = 1 + f xs -- La lista ha almeno un elemento, che è minore di zero f [] = 0 -- La lista è vuota