2014-04-16 12 views
18

Il codice è qui sotto:modello illegale in mappa di Erlang

-module(map_demo). 
-export([count_characters/1]). 

count_characters(Str) -> 
count_characters(Str, #{}). 

count_characters([H|T], #{ H => N } = X) -> 
    count_characters(T, X#{ H := N+1 }); 
count_characters([H|T], X) -> 
    count_characters(T, X#{ H => 1}); 
count_characters([], X) -> 
    X. 

durante la compilazione del codice nel guscio Erlang, ha segnalato i seguenti errori:

1> c(map_demo). 
map_demo.erl:7: illegal pattern 
map_demo.erl:8: variable 'N' is unbound 
map_demo.erl:10: illegal use of variable 'H' in map 
map_demo.erl:7: Warning: variable 'H' is unused 
error 

Sono nuovo in Erlang, e proprio non riesco a trovare nulla di sbagliato da solo. Come correggerlo?

+2

La cosa più vicina che riesco a trovare è che si tratta di un "bug noto". Queste persone erlang sono serie? Questo è un bug così grande in quel caso! Penso che questo sia qualcosa che hai preso da "Programming Erlang" di Joe Armstrong stesso, e sono scioccato dal fatto che questo non funzioni! –

+0

A partire da Erlang/OTP 18.0 questo codice genera l'errore "solo" per la riga 7, 8 perché le variabili associate sono legali da utilizzare nelle mappe: ________________________________________________________________________________ 1> 'K = thecake, # {K => isalie} .' _______________________________________________' # { thecake => isalie} ' –

+0

esegue la versione 20, e questo è ANCORA un errore ?! Forse cercherò un po 'di più prima di arrabbiarmi, ma ... https://stackoverflow.com/questions/44247735/map-pattern-matching-in-erlang-unexpected-error-unbound – alexakarpov

risposta

15

Le risposte da IRC (# erlang @ freenode):

  1. variabili come tasti in partite non sono ancora supportati (versione 17.0)
  2. Una questione più generale riguarda corrispondenti argomenti di una funzione: la riga 7 H viene abbinata 2 volte; o una volta e usato per abbinare N quindi. (Questo problema appare anche con i binari)

Questo dovrebbe essere risolto nelle prossime versioni.

A partire dalla release 17 this opere:

-module(count_chars). 
-export([count_characters/1]). 

count_characters(Str) -> 
     count_characters(Str, #{}). 

%% maps module functions cannot be used as guards (release 17) 
%% or you'll get "illegal guard expression" error 
count_characters([H|T], X) -> 
    case maps:is_key(H,X) of 
     false -> count_characters(T, maps:put(H,1,X)); 
     true -> Count = maps:get(H,X), 
         count_characters(T, maps:update(H,Count+1,X)) 
    end; 
count_characters([], X) -> 
     X. 

Ecco un'altra versione (testato solo su 18), che è un po 'più simile a quella del libro:

-module(count_chars). 
-export([count_characters/1]). 

count_characters(Str) -> 
     count_characters(Str, #{}). 

count_characters([H|T], X) -> 
    case maps:is_key(H,X) of 
     false -> count_characters(T, X#{ H => 1 }); 
     true -> #{ H := Count } = X, 
       count_characters(T, X#{ H := Count+1 }) 
    end; 
count_characters([], X) -> 
     X. 
+1

Poiché (1) è il caso, qual è il modo corretto di scrivere questo codice utilizzando le mappe in 17.0? – JDong

-1

Problema nella sintassi della corrispondenza.

Partita partita :=. Esempio

test(#{ key := Test }) -> Test.

e per la chiave e il valore associato all'uso =>. Esempio: M = #{ keynew => 123 }

+0

Quindi, come correggere il codice? Ho appena provato il tuo metodo. Ma non funziona. – geeker

+0

Mi dispiace, ho saltato un momento. Se si utilizza la mappa, la chiave non è variabile, è necessario utilizzare # {chiave => Valore}. – saa

-1

Suppongo che si stia utilizzando R17 poiché questa funzione è disponibile solo da questa versione.

guardando qualcosa in proposito, la mia comprensione è che si dovrebbe scrivere il codice in questo modo (non posso provarlo, sto ancora utilizzando R15: o)

-module(map_demo). 
-export([count_characters/1]). 

count_characters(Str) -> 
count_characters(Str, #{}). 

count_characters([H|T], #{ H := N } = X) -> 
    count_characters(T, X#{ H := N+1 }); 
count_characters([H|T], X) -> 
    count_characters(T, X#{ H => 1}); 
count_characters([], X) -> 
    X. 
-2

-module (count_chars) .

%% API

Export ([count/1]).

count (Str) -> count_chars (Str, mappe: new()).

count_chars ([H | T], Mappa) quando is_map (Map) ->

N = maps:get(H, Map, 0), 
count_chars(T, maps:put(H, N + 1, Map)); 

count_chars ([], Mappa) -> Mappa.

+0

Si prega di approfondire cosa è stato modificato per far funzionare correttamente questa risposta. Dare solo il codice non aiuta a chiarire cosa è stato sbagliato in primo luogo. – EWit

2

Citato da OTP 17.0 Release Notes:

OTP-11616 == erts stdlib hipe dialyzer compilatore typer ==

EEP43: New data type - Maps 

    With Maps you may for instance: 

    -- M0 = #{ a => 1, b => 2}, % create associations 

    -- M1 = M0#{ a := 10 }, % update values 

    -- M2 = M1#{ "hi" => "hello"}, % add new associations 

    -- #{ "hi" := V1, a := V2, b := V3} = M2. % match keys with 
    values 

    For information on how to use Maps please see the Reference 
    Manual. 

    The current implementation is without the following features: 

    -- No variable keys 

    -- No single value access 

    -- No map comprehensions 

    Note that Maps is experimental during OTP 17.0. 

Attualmente è possibile utilizzare il modulo maps per implementare count_characters:

count_characters(Str) -> 
    count_characters(Str, #{}). 

count_characters([H|T], X) -> 
    count_characters(T, maps:put(H, maps:get(H, X, 0) + 1, X)); 
count_characters([], X) -> 
    X. 
1

@EWit, Felipe Mafra:

mappe fa esattamente quello che deve fare; ciò che manca qui è la parte di riduzione:

count(Str) -> M = count_chars(Str, maps:new()), % maps part, bad naming 
    L = maps:to_list(M),      % to be able to sum 
    N = [X || {_,X} <- L],      % strip the numbers 
    lists:sum(N).        % sum them up 

count_chars([H|T], Map) when is_map(Map)-> 
    N = maps:get(H, Map, 0), 
    count_chars(T, maps:put(H, N + 1, Map)); 
count_chars([], Map) -> Map.