関数でreturnを明示的に呼び出すかどうか


199

しばらく前、Rコアチーム(私は信じています)からSimon Urbanekに、ユーザーにreturn関数の最後に明示的に呼び出すよう勧めることで非難されました(ただし、彼のコメントは削除されました)。

foo = function() {
  return(value)
}

代わりに彼は推奨しました:

foo = function() {
  value
}

おそらくこのような状況ではそれが必要です:

foo = function() {
 if(a) {
   return(a)
 } else {
   return(b)
 }
}

彼のコメントreturnは、厳密に必要とされない限り電話をかけないことがなぜ良いのかについていくつかの光を投げかけましたが、これは削除されました。

私の質問は次のとおりです。なぜreturn、より速く、またはよりよく電話をかけないので、望ましいのですか?


12
return最後の例でも不要です。削除returnすると少し速くなるかもしれませんが、私の考えでは、これはRが機能的なプログラミング言語であると言われているためです。
kohske

4
@kohskeコメントを拡張して、なぜそれがより速いのか、これが関数型プログラミング言語であるRとどのように関連しているかについての詳細を含めてください。
Paul Hiemstra

2
return非ローカルジャンプを誘発し、明示的な非ローカルジャンプはFPでは珍しいです。実際には、例えば、スキームにはありませんreturn。私のコメントは回答として短すぎる(そしておそらく間違っている)と思います。
kohske 2012

2
F#はありませんreturnbreakcontinue退屈時々ある、のいずれか。
colinfang 2013

回答:


129

質問は次のとおりです。なぜ(明示的に)リターンをより速くまたはよりよく呼び出さないため、望ましいのでしょうか。

Rのドキュメントには、そのような仮定を行うステートメントはありません。
メインページ? '関数'は言う:

function( arglist ) expr
return(value)

returnを呼び出さずに高速ですか?

function()return()は両方ともプリミティブ関数であり、関数function()を含めなくても、それ自体が最後に評価された値を返しますreturn()

引数として最後の値return()を使用.Primitive('return')して呼び出すと、同じ処理が行われますが、もう1回呼び出す必要があります。そのため、この(多くの場合)不要な.Primitive('return')呼び出しは、追加のリソースを引き出すことができます。ただし、単純な測定では、結果の差が非常に小さいため、明示的な戻り値を使用しない理由にはなりません。次のプロットは、この方法で選択されたデータから作成されます。

bench_nor2 <- function(x,repeats) { system.time(rep(
# without explicit return
(function(x) vector(length=x,mode="numeric"))(x)
,repeats)) }

bench_ret2 <- function(x,repeats) { system.time(rep(
# with explicit return
(function(x) return(vector(length=x,mode="numeric")))(x)
,repeats)) }

maxlen <- 1000
reps <- 10000
along <- seq(from=1,to=maxlen,by=5)
ret <- sapply(along,FUN=bench_ret2,repeats=reps)
nor <- sapply(along,FUN=bench_nor2,repeats=reps)
res <- data.frame(N=along,ELAPSED_RET=ret["elapsed",],ELAPSED_NOR=nor["elapsed",])

# res object is then visualized
# R version 2.15

関数経過時間比較

上の画像は、ご使用のプラットフォームでは多少異なる場合があります。測定されたデータに基づいて、返されたオブジェクトのサイズは違いを引き起こしていません。繰り返しの数(スケールアップされている場合でも)は、非常に小さな違いをもたらします。これは、実際のデータと実際のアルゴリズムではカウントできず、スクリプトの実行が速くなります。

リターンを呼び出さない方がいいですか?

Return ルーチンが終了し、関数から飛び出し、値を返す場所でコードの「リーフ」を明確に設計するための優れたツールです。

# here without calling .Primitive('return')
> (function() {10;20;30;40})()
[1] 40
# here with .Primitive('return')
> (function() {10;20;30;40;return(40)})()
[1] 40
# here return terminates flow
> (function() {10;20;return();30;40})()
NULL
> (function() {10;20;return(25);30;40})()
[1] 25
> 

プログラマーの戦略とプログラミングスタイルによって異なりますが、return()は不要なので使用できません。

Rコアプログラマーは両方のアプローチを使用します。「ベース」関数のソースで見つけることができるので、明示的なreturn()の有無にかかわらず。

多くの場合、関数を完全に停止するためにreturn()のみが使用され(引数なし)、NULLが返されます。

Rを使用する標準ユーザーまたはアナリストが実際の違いを認識できないため、それがより良いかどうかは明らかではありません。

私の意見では、質問は次のとおりですR実装からの明示的なリターンを使用することに危険はありますか?

または、多分、より良い、ユーザーの書き込み機能コード常に尋ねる必要があります。で効果は何であるではない、明示的なリターンを使用して(またはコードブランチの最後の葉として返されるオブジェクトを配置する)機能コードでは?


4
非常に良い答えをありがとう。を使用しても危険はないと私は思いますreturn。それを使用するかどうかは、プログラマーの好みにかかっています。
Paul Hiemstra、

38
の速度returnは本当に心配する必要がある最後のものです。
ハドリー2014年

2
これは悪い答えだと思います。その理由は、不必要なreturn関数呼び出しを使用することの価値の根本的な不一致に帰着します。あなた尋ねるべき質問は、あなたが最後に提案するものではありません。代わりに、「なぜ冗長を使用する必要があるのreturnですか?どのようなメリットがありますか?」結局のところ、答えは「あまりない」、または「まったくない」です。あなたの返事はこれを正しく評価できません。
Konrad Rudolph

@KonradRudolph ...あなたは実際にポールが最初に求めていたことを繰り返しました(なぜ明示的な復帰が悪いのですか)。そして、私は正しい(誰にとっても正しい)答えも知りたいです:)。このサイトのユーザーに説明を提供することを検討しますか?
Petr Matousu 2017年

1
@Dason私は他の場所でRedditの投稿をリンクして、この議論がこのコンテキストで欠陥がある理由を説明しています。残念ながら、コメントは毎回自動的に削除されるようです。短いバージョンは、return「xを1増やす」という明示的なコメントのようなもので、コードの一部がの横にありますx = x + 2。言い換えると、その明示性は(a)まったく無関係であり、(b)間違った情報を伝えます。のでreturnRでの意味は、純粋に、 『この機能アボート』です。他の言語と同じという意味ではありませreturn
Konrad Rudolph

103

誰もがそれに同意した場合

  1. return 関数の本体の最後には必要ありません
  2. 使用しないことreturnはわずかに高速です(@Alanのテストによると、5.1に対して4.3マイクロ秒)

return関数の最後で使用を停止する必要がありますか?私は確かにそうしません。その理由を説明したいと思います。他の人が私の意見を共有してくれるか聞いてみたいです。そして、それがOPに対する正解ではなく、長い主観的なコメントのようである場合は、謝罪します。

使用しないことに伴う私の主な問題returnは、Paulが指摘したように、関数の本体には必要な場所がほかにもあるということです。またreturn、関数の途中で使用することを余儀なくされた場合は、すべてのreturnステートメントを明示的にしないでください。私は矛盾しているのが嫌いです。また、コードの方が読みやすいと思います。関数をスキャンして、すべての出口点と値を簡単に確認できます。

Paulはこの例を使用しました:

foo = function() {
 if(a) {
   return(a)
 } else {
   return(b)
 }
}

残念ながら、次のように簡単に書き直すことができると指摘できます。

foo = function() {
 if(a) {
   output <- a
 } else {
   output <- b
 }
output
}

後者のバージョンは、関数ごとに1つのreturnステートメントを提唱するいくつかのプログラミングコーディング標準にも準拠しています。より良い例は次のようになったと思います:

bar <- function() {
   while (a) {
      do_stuff
      for (b) {
         do_stuff
         if (c) return(1)
         for (d) {
            do_stuff
            if (e) return(2)
         }
      }
   }
   return(3)
}

これは、単一のreturnステートメントを使用して書き換えるのがはるかに難しくなります。複数breakのと、それらを伝播するためのブール変数の複雑なシステムが必要になります。これはすべて、単一の戻り規則がRではうまく機能しないことを意味します。そのためreturn、関数の本体のいくつかの場所で使用する必要がある場合は、一貫してどこでも使用しないでください。

速度の引数は有効なものではないと思います。実際に何かを行う関数を調べ始めると、0.8マイクロ秒の違いはありません。私が見ることができる最後のものは、それはタイピングが少ないということですが、ちょっと、私は怠惰ではありません。


7
+ 1、return@ flodelが示したように、場合によってはステートメントの明確な必要性があります。あるいは、returnステートメントを省略したほうがよい場合もあります(たとえば、多数の小さな関数呼び出しなど)。それ以外の場合、たとえば95%と言ってもreturn、使用するかしないかは問題ではなく、好みによるものです。returnはあなたが何を意味するのかがより明確で、より読みやすいので、私はreturnを使うことが好きです。多分この議論は<-vsに似てい=ますか?
Paul Hiemstra

7
これはRを命令型プログラミング言語として扱いますが、そうではありません。それは関数型プログラミング言語です。関数型プログラミングは単純に動作が異なり、return値を返すためにを使用することは、のif (x == TRUE)代わりに書くことと同じくらい無意味ですif (x)
Konrad Rudolph、

4
また、次のように書き換えfooますfoo <- function(x) if (a) a else b(必要に応じて改行します)。明示的な戻り値や中間値は必要ありません。
ハドリー2014年

26

これは興味深い議論です。@flodelの例は素晴らしいと思います。ただし、関数型コーディングスタイルではなく命令型returnを使用する場合に意味がある私のポイント(および@koshkeがコメントでこれを言及している)を示していると思います。

重要なことではありませんが、私は次のように書き直したでしょうfoo

foo = function() ifelse(a,a,b)

関数スタイルは、の値の保存など、状態の変更を回避しますoutput。このスタイルでreturnは、場違いです。foo数学関数のように見えます。

私は@flodelに同意する:にブール変数の複雑なシステムを使用してbar、あなたが持っているときあまり明確で、かつ無意味だろうreturn。何がbarにとても適しreturn文は、それが不可欠なスタイルで書かれていることです。実際、ブール変数は、関数スタイルで回避された「状態」の変化を表しています。

bar単なる擬似コードであるため、関数形式で書き直すのは本当に難しいですが、アイデアは次のようなものです。

e_func <- function() do_stuff
d_func <- function() ifelse(any(sapply(seq(d),e_func)),2,3)
b_func <- function() {
  do_stuff
  ifelse(c,1,sapply(seq(b),d_func))
}

bar <- function () {
   do_stuff
   sapply(seq(a),b_func) # Not exactly correct, but illustrates the idea.
}

whileそれが状態変化によって制御されているので、ループは、書き換えが最も困難であろうa

への呼び出しによる速度の低下returnは無視できますが、return関数形式での回避と書き換えによって得られる効率は、非常に大きなものになることがよくあります。新しいユーザーに使用をやめるように言ってreturnも役に立たないかもしれませんが、機能的なスタイルに誘導することには効果があります。


@Paul returnは、ループ内のさまざまなポイントで関数を終了することがよくあるため、命令スタイルで必要です。関数スタイルはループを使用しないため、を必要としませんreturn。純粋に機能的なスタイルでは、最後の呼び出しはほとんど常に目的の戻り値です。

Pythonでは、関数にはreturnステートメントが必要です。ただし、関数スタイルで関数をプログラミングした場合は、関数returnの最後にステートメントが1つしかありません。

別のStackOverflow投稿の例を使用TRUEして、指定されたすべての値のx長さが奇数である場合に返される関数が必要だとしましょう。2つのスタイルを使用できます。

# Procedural / Imperative
allOdd = function(x) {
  for (i in x) if (length(i) %% 2 == 0) return (FALSE)
  return (TRUE)
}

# Functional
allOdd = function(x) 
  all(length(x) %% 2 == 1)

関数形式では、返される値は当然関数の最後にあります。繰り返しますが、それは数学関数のように見えます。

@GSeeで説明されて?ifelseいる警告は間違いなく興味深いものですが、関数の使用をやめさせようとしているとは思いません。実際にifelseは、関数を自動的にベクトル化するという利点があります。たとえば、少し変更したバージョンを考えてみfooます。

foo = function(a) { # Note that it now has an argument
 if(a) {
   return(a)
 } else {
   return(b)
 }
}

この関数length(a)は、1の場合に正常に機能します。ただしfooifelse

foo = function (a) ifelse(a,a,b)

fooの任意の長さで動作しますa。実際、aが行列の場合でも機能します。testベクトル化に役立つ機能と同じ形状の値を返すことは問題ではありません。


なぜreturn関数型のプログラミングに適合しないのかははっきりしません。命令型または関数型のプログラミングであるかどうかにかかわらず、ある段階で、関数またはサブルーチンは何かを返す必要があります。たとえば、Pythonでの関数型プログラミングにはまだreturnステートメントが必要です。この点について詳しく説明していただけますか。
Paul Hiemstra

このような状況では、使用ifelse(a,a,b)は私のピーターピーチです。のすべての行が?ifelse「の代わりに私を使用しないでください」と叫んでいるようですif (a) {a} else b。例: "...は"と同じ形状の値を返します。 " またはtest" 短すぎる場合、要素は再利用されます。 "、"結果のモードは"、"の値に依存する可能性があります結果のクラス属性取られるから選択された値のために不適切であってもよいし、「yesnotesttestyesno
GSee

一見すると、fooあまり意味がありません。常にTRUEまたはを返しbます。これを使用ifelseすると、1つまたは複数のTRUE、または1つまたは複数bのs が返されます。最初、この関数の目的は、「あるステートメントがTRUEの場合は何かを返し、それ以外の場合は別の何かを返す」と言うことだと思いました。それは、リターンをTRUEあるいくつかのオブジェクトの要素を返し、TRUEではありませんすべての要素の」なるので、私は、それがベクトル化されなければならないとは思わないb
GSee

22

それなしreturn()ではより速いようです...

library(rbenchmark)
x <- 1
foo <- function(value) {
  return(value)
}
fuu <- function(value) {
  value
}
benchmark(foo(x),fuu(x),replications=1e7)
    test replications elapsed relative user.self sys.self user.child sys.child
1 foo(x)     10000000   51.36 1.185322     51.11     0.11          0         0
2 fuu(x)     10000000   43.33 1.000000     42.97     0.05          0         0

____ 編集__ _ __ _ __ _ __ _ __ _ ___

他のベンチマーク(benchmark(fuu(x),foo(x),replications=1e7))に進むと、結果が逆になります...サーバーで試してみます。


この違いが発生する理由についてコメントしていただけますか?
Paul Hiemstra、2012

4
@PaulHiemstra Petrの回答は、これの主な理由の1つをカバーしています。を使用する場合は2つの呼び出し、使用return()しない場合は1つ。function()最後の値を返すため、関数の最後では完全に冗長です。これは、関数return()の総計算時間の大部分がコストになるように、内部であまり実行されない関数の多くの繰り返しでのみ気付きます。
Gavin Simpson、

13

「return」を明示的に最後に置かないことの問題は、メソッドの最後にステートメントを追加すると、突然、戻り値が間違っていることです。

foo <- function() {
    dosomething()
}

これはの値を返しますdosomething()

これで、次の日に来て、新しい行を追加します。

foo <- function() {
    dosomething()
    dosomething2()
}

コードがの値を返すことを望んdosomething()でいましたが、代わりにそれはもはや行いません。

明示的な復帰により、これは本当に明白になります:

foo <- function() {
    return( dosomething() )
    dosomething2()
}

このコードに奇妙な点があることがわかり、修正します。

foo <- function() {
    dosomething2()
    return( dosomething() )
}

1
はい、実際には、デバッグ時に明示的なreturn()が役立つことがわかりました。コードがクリーンアップされると、その必要性はそれほど魅力的ではなくなり、私はそれを持たない優雅さを好みます...
PatrickT

しかし、これは実際には実際のコードの問題ではなく、純粋に理論的なものです。これに悩まされる可能性のあるコードには、はるかに大きな問題があります。それは、単純な追加がそれを壊すほど明白ではない、あいまいで脆いコードフローです。
Konrad Rudolph

@KonradRudolph私はあなたがそれに対して真のスコットランド人をやっていると思います;-)「これがあなたのコードの問題であるならば、あなたは悪いプログラマーです!」。私は本当に同意しません。私はあなたがすべての行を心で知っている小さなコードの部分でショートカットを取ることで逃げることができる一方で、コードが大きくなるにつれてこれはあなたを噛むように戻ってくると思います。
ヒューパーキンス

2
@HughPerkins 真のスコットランド人でありません。むしろ、これは数十年に及ぶソフトウェアエンジニアリングのベストプラクティスに裏付けられた、コードの複雑さに関する経験的な観察です。つまり、個々の関数を短くし、コードフローを明確にします。省略returnはショートカットではなく、関数型プログラミングの適切なスタイルです。不必要なreturn関数呼び出しの使用は、カーゴカルトプログラミングのインスタンスです。
Konrad Rudolph

まあ...私はこれがどのようにあなたのreturnステートメントの後に何かを追加するのを防ぎ、それが実行されないことに気付かないのかわかりません。返す値の後にコメントを追加することもできます。例dosomething() # this is my return value, don't add anything after it unless you know goddam well what you are doing
lebatsnok

10

私の質問は次のとおりです。なぜreturnより速く電話をかけないのですか

returnはRの(プリミティブ)関数です。つまり、コードで使用すると関数呼び出しのコストが発生するため、処理が高速になります。これを他のほとんどのプログラミング言語と比較します。ここreturnで、はキーワードですが、関数呼び出しではありません。ランタイムコードの実行には変換されません。

とは言っても、この方法でプリミティブ関数を呼び出すと、Rではかなり高速になり、呼び出しreturnを行うと非常に小さなオーバーヘッドが発生します。これは、を省略することについての議論ではありませんreturn

以上、したがって、好ましいですか?

使う理由ないから。

それは冗長であり、有用な冗長性を追加しないからです

明確にするために、冗長性役立つ場合あります。しかし、ほとんどの冗長性はこの種のものではありません。代わりに、情報を追加せずに視覚的な混乱を追加する種類のものです。これは、フィラーワードまたはチャートジャンクに相当するプログラミングです。

次の説明コメントの例を考えてみましょう。コメントは、コードがすでに表現していることを単に言い換えただけなので、冗長性が悪いと広く認識されています。

# Add one to the result
result = x + 1

returnRは関数型プログラミング言語であり、Rではすべての関数呼び出しに値があるため、Rでの使用は同じカテゴリに分類されます。これは、基本的な Rの性質そして、あなたは(すべての関数呼び出しを含む)すべての式が値を持っていることの観点からRコードが表示されたら、問題はその後になり:「なぜべきで、私が使用してreturn?」デフォルトでは使用しないので、前向きな理由が必要です。

そのような肯定的な理由の1つは、関数からの早期終了を通知することです(ガード節など)

f = function (a, b) {
    if (! precondition(a)) return() # same as `return(NULL)`!
    calculation(b)
}

これは、の有効な非冗長使用ですreturn。ただし、そのようなガード句は他の言語と比較してRではまれであり、すべての式に値があるため、正規表現ifは次のことを必要としませんreturn

sign = function (num) {
    if (num > 0) {
        1
    } else if (num < 0) {
        -1
    } else {
        0
    }
}

次のfように書き換えることもできます。

f = function (a, b) {
    if (precondition(a)) calculation(b)
}

…はとif (cond) expr同じif (cond) expr else NULLです。

最後に、3つの一般的な異論を未然に防ぎたいと思います。

  1. 一部の人々は、return「この関数は値を返す」というシグナルを送るため、使用することで明快さが増すと主張しています。しかし、上記で説明したように、すべての関数はRで何かを返します。return値を返すマーカーは、冗長であるだけでなく、誤解を招く可能性があります。

  2. 関連して、Zen of Pythonには常に従うべき素晴らしいガイドラインがあります。

    明示的は暗黙的よりも優れています。

    冗長性の削除returnはこれに違反しないのですか?関数型言語の関数の戻り値は常に明示的であるため、それは最後の式です。これは、再び明示ほぼ同じ引数であるの冗長性。

    実際、明示的にしたい場合は、それを使用してルールの例外を強調します。意味のある値を返さない関数にマークを付けます。これらの関数は、副作用などのためにのみ呼び出されます(などcat)。ただし、Rにはreturnこのケースよりも優れたマーカーがありますinvisible。たとえば、私は書きます

    save_results = function (results, file) {
        # … code that writes the results to a file …
        invisible()
    }
  3. しかし、長い関数はどうですか?返却されたものを見失うのは簡単ではないでしょうか?

    2つの答え:最初に、そうではありません。ルールは明確です。関数の最後の式はその値です。追跡するものは何もありません。

    しかし、より重要なのは、長い関数の問題は、明示的なreturnマーカーがないことではありません。関数長さです。長い関数はほぼ(?)常に単一の責任の原則に違反し、そうでない場合でも、読みやすくするために分解することで利益を得ます。


多分私はreturnそれを他の言語にもっと似せるために使うことを擁護している人々がいることを付け加えるべきでしょう。しかし、それは悪い議論です。他の関数型プログラミング言語returnもどちらも使用しない傾向があります。それを使用するのは、すべての式に値があるわけではない、命令型言語だけです。
Konrad Rudolph、

私はreturnサポートを明示的に使用する方が良いとの意見でこの質問に行き、完全な批判をもってあなたの答えを読みました。あなたの答えは私にその見解を反映させるようにさせました。をreturn明示的に(少なくとも私自身の場合)に使用する必要性は、後で関数をより適切に修正できるようにする必要性に結びついていると思います。私の関数は単純に複雑すぎるかもしれないという考えで、プログラミングスタイルを改善するための目標は、コードを構造化してなしで明示的に維持するよう努力することであることがわかりreturnます。それらの反省と洞察をありがとう!!
Kasper Thystrup Karstensen

6

returnトリックだと思います。一般的なルールとして、関数で評価された最後の式の値が関数の値になります。この一般的なパターンは多くの場所にあります。以下のすべてが3と評価されます。

local({
1
2
3
})

eval(expression({
1
2
3
}))

(function() {
1
2
3
})()

returnが実際値を返すのではなく(これはその値の有無にかかわらず行われます)、関数を不規則に「抜け出す」ことになります。その意味では、RのGOTOステートメントに最も近いものです(breakとnextもあります)。return関数の最後に使用することはほとんどなく、決して使用しません。

 if(a) {
   return(a)
 } else {
   return(b)
 }

...これは、if(a) a else b読みやすく、中括弧の少ないものに書き換えることができます。returnここではまったく必要ありません。「return」を使用する私の典型的なケースは、次のようなものです...

ugly <- function(species, x, y){
   if(length(species)>1) stop("First argument is too long.")
   if(species=="Mickey Mouse") return("You're kidding!")
   ### do some calculations 
   if(grepl("mouse", species)) {
      ## do some more calculations
      if(species=="Dormouse") return(paste0("You're sleeping until", x+y))
      ## do some more calculations
      return(paste0("You're a mouse and will be eating for ", x^y, " more minutes."))
      }
   ## some more ugly conditions
   # ...
   ### finally
   return("The end")
   }

一般に、多くのリターンの必要性は、問題が醜いか、構造が悪いことを示唆しています。

<>

return 関数が機能する必要はありません。評価する式のセットから抜け出すために使用できます。

getout <- TRUE 
# if getout==TRUE then the value of EXP, LOC, and FUN will be "OUTTA HERE"
# .... if getout==FALSE then it will be `3` for all these variables    

EXP <- eval(expression({
   1
   2
   if(getout) return("OUTTA HERE")
   3
   }))

LOC <- local({
   1
   2
   if(getout) return("OUTTA HERE")
   3
   })

FUN <- (function(){
   1
   2
   if(getout) return("OUTTA HERE")
   3
   })()

identical(EXP,LOC)
identical(EXP,FUN)

今日、私は1つが実際に必要があるかもしれませんケース見つかったreturn値であるかどうかをテストする必要があるとします(私の醜い例上記は非常に人工的である)NULLか、NAそうでない場合は返す、これらのケースでは、空の文字列を返す:character値を。しかし、のテストでis.na(NULL)はエラーが発生するため、でのみ実行できif(is.null(x)) return("")、で続行できるように見えif(is.na(x)) .....ます。(一つは使用することができるlength(x)==0代わりにis.null(x)、それでも、それを使用することはできませんlength(x)==0 | is.na(x)場合xですNULL。)
lebatsnok

1
これ|は、||(両側が評価されるベクトル化されたOR)を(述語が順番に評価されるベクトル化されていない短絡OR )の代わりに使用したためです。if (TRUE | stop()) print(1)対の検討if (TRUE || stop()) print(1)
asac

2

return コードを読みやすくすることができます:

foo <- function() {
    if (a) return(a)       
    b     
}

3
多分それはそれでできます。しかし、それはあなたの例ではそれをしません。代わりに、コードフローを覆い隠します(または、むしろ複雑にします)。
Konrad Rudolph

1
関数は次のように簡略化できますfoo <- function() a || b(これはIMOの方が読みやすいです。いずれにしても、「純粋な」読みやすさはありませんが、誰かの意見では読みやすさがあります。アセンブリ言語は完全に読みやすいと言う人がいます)
lebatsnok

1

冗長性の議論はここで多く出てきました。私の見解では、それは省略するのに十分な理由ではありませんreturn()。冗長性は自動的に悪いことではありません。戦略的に使用すると、冗長性によりコードがより明確になり、保守しやすくなります。

次の例を検討してください。関数のパラメータには、多くの場合デフォルト値があります。したがって、デフォルトと同じ値を指定することは冗長です。それを除いて、私が期待する動作を明らかにします。デフォルトを確認するために関数のマンページを開く必要はありません。また、関数の将来のバージョンでデフォルトが変更される心配はありません。

呼び出しのパフォーマンスペナルティはごくわずかですがreturn()(他のユーザーがここに掲載したベンチマークに従って)、正しいか間違っているかではなく、スタイルに影響します。何かが「間違っている」ためには、明らかな不利益がある必要があり、ここに誰も含めたり除外したりreturn()することで一貫した不利益があることを十分に実証していません。非常にケース固有でユーザー固有のようです。

だから私はこれに立ち向かう場所です。

function(){
  #do stuff
  ...
  abcd
}

上記の例のように、「孤立した」変数に不快です。たabcd私は書き込みが完了しなかった文の一部になるだろうか?それは私のコードのスプライス/編集の残りであり、削除する必要がありますか?誤って他の場所から何かを貼り付け/移動しましたか?

function(){
  #do stuff
  ...
  return(abdc)
}

対照的に、この2番目の例では、偶然のコードや不完全なコードではなく、意図した戻り値であることを明確に示しています。私にとって、この冗長性はまったく役に立ちません。

もちろん、関数が完成して動作したら、戻り値を削除できます。しかし、それを削除すること自体は冗長な余分なステップであり、私の見解return()では、最初に含めるよりも役に立たないと考えています。

そうは言っても、私はreturn()名前のない短い1行関数では使用しません。そこでは、関数のコードの大部分を占めており、そのため、コードを読みにくくする視覚的な混乱を主に引き起こしています。しかし、正式に定義され、名前が付けられたより大きな関数の場合は、それを使用します。


「abcdは私が書き終えなかった声明の一部になるのでしょうか?」— しかし、これはあなたが書く他の表現とどう違うのですか?これが私たちの意見の相違の核心だと思います。変数を自立させることは、命令型プログラミング言語に特有のことかもしれませんが、関数型プログラミング言語では完全に正常であり、期待されています。私が主張する問題は、単に関数型プログラミングに慣れていないことです(「式」ではなく「ステートメント」について話すという事実がこれを補強します)。
Konrad Rudolph

他のすべてのステートメントは通常、より明白な方法で何かを行うため、違います。それは、割り当て、比較、関数呼び出しです...はい、私の最初のコーディング手順は命令型言語でしたが、依然として命令型言語を使用しています。言語間で視覚的な合図を統一すると(言語が許可するところならどこでも)、私の作業が簡単になります。A return()in Rは無料です。それは客観的に冗長ですが、「役に立たない」ことはあなたの主観的な判断です。冗長で役に立たないことは必ずしも同義語ではありません。それは私たちが反対するところです。
サイモン

また、私はソフトウェアエンジニアでもコンピューターサイエンティストでもありません。私の専門用語の使用について、あまりニュアンスを読みすぎないでください。
サイモン

明確にするために:「冗長で役に立たないことは必ずしも同義語ではありません。それが私たちが反対するところです。」—いいえ、私はそれに完全に同意し、私はその点を私の回答で明確に述べました。冗長性は役立つ場合もあれば、重要な場合もあります。しかし、これは積極的に示される必要があり、想定されていません。これがに当てはまると考える理由についてのあなたの主張を理解しました。return私が確信していないとしても、それは潜在的に有効であると思います(間違いなく命令型言語です...私の信念は、関数型言語に変換されないということです)。
Konrad Rudolph、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.