Schemeのプログラミング うるう年関連
Schemeで、
「(1)閏年かどうかを判定する関数leap?(number -> boolean)を定義した後、(2)○年○月の日数は何日かを求める関数num-of-days(number number -> number)を定義せよ」
という内容の課題を出されたのですが、(例えば 2009年の7月→31日 2012年の2月→29日)
どうもエラーが出て実行できません。
自分は以下のように組みました。
;;(1)の関数
(define (leap? year)
(cond
[(= (remainder year 400) 0) #t]
[(and (= (remainder year 4) 0)(> (remainder year 100) 0)) #t]
[else #f]
)
)
;;(2)の関数
(define (num-of-days year month)
(cond
[(and (= month 2)(= (leap? year) #t)) 29]
[(and (= month 2)(= (leap? year) #f)) 28]
[(or (= month 1)(= month 3)(= month 5)
(= month 7)(= month 8)(= month 10)
(= month 12)) 31]
[else 30]
)
)
これを例えば
(num-of-days 2008 4) や (num-of-days 1995 12)
などとして実行すると、それぞれ30,31という正しい値を返してくれるのですが、
(num-of-days 2008 2) や (num-of-days 1995 2)
など、閏年・非閏年に関係無く、2月が絡むと
=: expects type <number> as 1st argument, given: false; other arguments were: true
というエラーを吐いてしまいます。
何度も見直しましたが、どこが間違っているのか見付けきれません…。どなたか間違いを指摘して頂けると幸いです。
No.3ベストアンサー
- 回答日時:
ああ、ちなみに。
manaka3161 さんの作ったコードのロジックは「無駄がある」とは思いますが、基本的に「間違ってはいない」、とは思いますよ。
どこが悪いのか?と言うと、単純に、ここです。
(define (num-of-days year month)
(cond
[(and (= month 2)(= (leap? year) #t)) 29] ;; ここが間違ってる
[(and (= month 2)(= (leap? year) #f)) 28] ;; ここが間違ってる
[(or (= month 1)(= month 3)(= month 5)
(= month 7)(= month 8)(= month 10)
(= month 12)) 31]
[else 30]
)
)
「ロジックが合ってる」のに「エラーを返す」場合があるんです。何故なら、データ型に整合性がない、からです。
比較演算子=は「数値専用」で等価判定を下す。引数が数値である、ってのが前提なんですけど、引数にシンボル#tか#fが来てる、ってのがエラーの原因です。
> (= 1 2)
#f
> (= 1 1)
#t
> (= 'a 'b)
=: expects type <number> as 1st argument, given: a; other arguments were: b
=== context ===
/usr/lib/plt/collects/scheme/private/misc.ss:74:7
>
同じエラーですよね。見て分かる通り、=は数値しか引数に取れないんです。
つまり、シンボル同士を比較したい場合はeq?使った方が良いでしょう。すなわち、
(define (num-of-days year month)
(cond
[(and (= month 2)(eq? (leap? year) #t)) 29] ;二番目の判定式を eq? で行う
[(and (= month 2)(eq? (leap? year) #f)) 28] ;二番目の判定式を eq? で行う
[(or (= month 1)(= month 3)(= month 5)
(= month 7)(= month 8)(= month 10)
(= month 12)) 31]
[else 30]
)
)
これで動く筈です。
> (num-of-days 2009 7)
31
> (num-of-days 2012 2)
29
>
慣れない内は、数値/シンボルの比較を両方「考えずに行いたい」のなら、eqv?を使った方が良いかもしれません。eqv?はリストじゃなければ数値/シンボルの両方とも行えます。eq?はシンボル専用、ですね。=は数値専用。
大まかに言うと、繰り返しになりますが、次のようになってます。
eq? => シンボル比較の時に使う。高速。
eqv? => 数値、シンボル両方O.K。ある意味デフォルト。
equal? => リスト同士まで比較出来る。ただし、eq?に比べると遅い。
= => 数値専用。
eq? => シンボル比較の時に使う。高速。
eqv? => 数値、シンボル両方O.K。ある意味デフォルト。
equal? => リスト同士まで比較出来る。ただし、eq?に比べると遅い。
= => 数値専用。
↑まさに私が求めていた解説でした!すごく分かり易くて、助かりました!
eq?を使用すれば、回りくどいけれども、あくまで自分の考えた内容でも通すことが出来るのですね。本当に有り難うございました。
No.2
- 回答日時:
;;; #t とか #f が返り値の場合、and や or 使った方がシンプル
(define (leap? year)
(and (zero? (modulo year 4))
(or (not (zero? (modulo year 100)))
(zero? (modulo year 400)))))
;;; こう言う場合、cond を使うとメンド臭いんで、case を使った方がシンプルに書けると思う
(define (num-of-days year month)
(case month
((1 3 5 7 8 10 12) 31)
((2) (if (leap? year) 29 28))
(else 30)))
caseはDrSchemeで認識してくれませんでした…。ですがifを使って補助関数を作成することで解決しました。有り難うございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP PHPの構文で間違えが分からない 5 2022/07/11 16:38
- PHP SQLとPHPの連結方法がわからないのでアドバイスお願い致します 1 2022/07/12 12:16
- PHP アコーディオンPHPが上手くいかない 3 2022/07/15 16:29
- Access(アクセス) アクセス 有効なフィールド名、または式として認識できませんのエラー 3 2022/08/19 11:53
- PHP style.cssのjQuery条件付きcssが機能しない 4 2022/07/17 18:27
- Access(アクセス) アクセス where句を使用して複数条件抽出をするには 2 2022/08/29 13:24
- Visual Basic(VBA) 今日の日付が過ぎたらその行を削除したい 1 2023/04/01 20:06
- Visual Basic(VBA) ①ExcelVBAでカレンダーを作り、別のユザーフォームで日付を入力したいのですがエラーになります。 1 2023/02/17 18:39
- 英語 "this day"が当日か今日を表すのかの使い分け方等について 5 2023/08/08 14:29
- Visual Basic(VBA) ExcelのVBAでシフト表を作っていますが、バグが出て困っています 2 2022/09/13 11:33
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
日齢計算プログラム
-
ソースの詳細を教えてください。
-
サマータイムの判定について
-
Application.ScreenUpdating = ...
-
formで特定のinputを送信しない...
-
文字の横にプルダウンを表示さ...
-
JSONで文字列が長い時
-
どちのほうがすきですか?
-
int(input("○○"))の使い方
-
実行時エラー 3020の対策
-
プルダウンで別項目に値を代入...
-
C言語のflagの使い方が分かりま...
-
16進の10進変換について
-
ACCESS テキストボックスを隙...
-
[html]ラジオボタンを使った診...
-
コンボボックスのtag情報の取得...
-
I2C接続のLCDディスプレイを使う
-
c言語 16進数の2進数への変換
-
Perlで複数の値を返す良い方法...
-
[python] 文字列を変数名として...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
質問
-
日付の差分の求め方(日、分)
-
前日の日付取得するには?
-
1桁の日付に0を付ける
-
当日の日付をプルダウンメニュ...
-
2つの日付・時間の差分を求め...
-
Perlの日付の比較に関して
-
体重が3kg増える/減る の英語...
-
Perlでsprintf("%02d",$month)...
-
「型が一致しません」のエラー...
-
C言語でのPICプログラミング
-
先月(YYYYMM)の生成方法
-
Cookieの有効期限について
-
Perlの日付取得で月の表示がお...
-
時間の計算について
-
更新記録CGIで「前へ」「次へ」...
-
pythonのプログラミングについ...
-
PHPメールフォームに入力された...
-
perlでcheckboxがうまく整理で...
-
if文データの別ファイル化について
おすすめ情報