2

私はErlangを初めて使っていて、一般的なプログラミングプログラミングには慣れていません。私のErlangプログラムの批評を探しています

私はErlangで本当に楽しい時間を過ごしています(Erlangの句読点は私が数回上がってしまったにもかかわらず);)しかし、私がフィードバックを得ることができたら、本当に大好きです より経験豊かなErlangのプログラマーのコードです。

私のコードは問題なく動作しているようですが、改善のために多くのアドバイスをいただけると確信しています。

-module(seqs). 
-export([takewhile/2, take/2]). 

%% Recursively pick elements from a lazy sequence while Pred(H) is true 
takewhile(Pred, [H|T]) -> 
    case Pred(H) of 
     true -> [H|takewhile(Pred, T())]; 
     false -> [] 
    end. 


%% Take a certain number of elements from a lazy sequence 
%% A non-tail recursive version 
take(0, _) -> []; 
take(Number, [H|T]) -> 
    [H|take(Number - 1, T())]. 

第二のモジュールは、実際の問題を解決します:)ここで

2nd Project Euler problemを解決するためのプログラムは、2つのモジュールに分割(でも素数400万以下のすべての合計を見つける。)です

-module(euler002). 
-import(seqs, [takewhile/2]). 
-export([lazyfib/0, solve/0]). 

%% Sums the numbers in a list (for practice's sake) 
sum([]) -> 0; 
sum([H|T]) -> H + sum(T). 


%% Practicing some list comprehensions as well! 
filter(P, Xs) -> [ X || X <- Xs, P(X) ]. 


%% Lazy sequence that generates fibonacci numbers 
lazyfib(A, B) -> [A | fun() -> lazyfib(B, A + B) end]. 
lazyfib() -> lazyfib(0, 1). 


%% Generate all fibonacci terms that are less than 4 million and sum the 
%% even terms 
solve() -> 
    Fibs = seqs:takewhile(fun (X) -> X < 4000000 end, lazyfib()), 
    sum(filter(fun (X) -> X rem 2 =:= 0 end, Fibs)). 

ありがとうございます。これがこの種類の質問に適したフォーラムでない場合は教えてください。 :)

+0

は、リストから、本当に何が違うのごtakewhile機能です:takewhile/2?また、あなたのテイク関数はlist:sublist/2に似ています。誰かがこれで私を修正する可能性がありますが、私はあなたの "seqs"関数が実際には意味がないので実際には怠惰だとは思わない。ハスケルは怠惰を使用します。 Erlangには無限リストはありません。 –

答えて

2

ここに一般的なヒントがあります。可能であれば、テール再帰を使用するようにしてください(練習のために)。例えば

、この関数は末尾再帰ではない:

%% Sums the numbers in a list (for practice's sake) 
sum([]) -> 0; 
sum([H|T]) -> H + sum(T). 

Hに添加することができるようにsum(T)の結果が返されなければならないからです。各再帰呼び出しは、呼び出しスタックに追加されます。多くの素数を合計するときなど、リストが大きすぎる場合は、メモリが不足したり、クラッシュしたりします。 、これは似ていますが

%% Hide the use of the accumulator, so caller can still use sum/1. 
%% Also note the period ending this function definition. 
sum(List) -> sum(List, 0). 
%% Sums the numbers in a list (for practice's sake) 
sum([], Acc) -> Acc; 
sum([H|T], Acc) -> sum(T, H + Acc). 

さらには最後の命令されて終わるの再帰呼び出し、前に行われていることに気づく:

は、このようなアキュムレータを使用して、機能の尾の再帰を行います。これはコンパイラが呼び出しの代わりにジャンプとして最適化できることを意味します(これは決してこの関数に戻る必要はないため)。膨大なコールスタックを作成しないでください。 sum/1から sum/2に行くとき

はまた、句読点のように注意してください。たとえ同じ名前であっても、異なるアリティを持つ関数は異なります。そのため、最初の行はセミコロンではなくピリオドで終わります。

希望に役立ちます。がんばろう。

+0

ありがとう! :)私は末尾再帰を使用して後続の問題を解決しようとしてきました。 Erlangの句読点は私には本当に2,3回悪いことがありましたが、今は慣れてきています。私は、句読点にも同様の問題があることを発見しました。EmacsのErlangモードが本当に知的に動作できるようになりました。 – Christoffer

0

Tidierでコードを実行することを検討してください。

http://tidier.softlab.ntua.gr:20000/tidier/getstarted

私はそれに短いプレゼンテーションを見て、それが作られたコードスタイルとLOCの最適化のいくつかは、単に驚異的でした。

+0

これはかなり良いツールです!私は最新のファイルで試してみましたが、コードを変更していない間に、それはさらにきれいになりました! ;)(私はあなたの答えをupvoteだろうが、私はまだ担当者がいない:P) – Christoffer

1

私はイテレータと発電機と一般機能のアプローチの美しさを理解し、とにかく簡単な解決策は、はるかに簡単でいいです:

-module(euler). 

-export([euler2/1]). 

euler2(Limit) -> euler2(Limit, 0, 1, 1). 

euler2(Limit, Sum, A, _B) when A > Limit -> Sum; 
euler2(Limit, Sum, A, B) -> 
    NewSum = case A rem 2 of 0 -> Sum+A; _ -> Sum end, 
    euler2(Limit, NewSum, B, A+B). 
関連する問題