3

私はHaskellを学び、学生のスケジュールを計画するのに役立つプログラムを作成しようとしている小さなプロジェクトに取り組んでいます。私は次のタイプを持っています:

data Course =
    { id :: Int, title :: String }
    deriving (Eq, Show)

data Req = Single Course
    | Any [Req]
    | All [Req]
    deriving Show

今、私はメソッドを書きたいです:

satisfies :: [Course] -> Req -> Bool

しかし、Reqに関する情報を使用して関数をオーバーロードする方法がわかりません。どうすればいいですか?

4

2 に答える 2

4

まず、いくつかのタイプミス:

data Course = Course { 
   id :: Int, 
   title :: String 
   } deriving (Eq, Show)

データコンストラクター名(「Course」)の追加と「derives」から「deriving」への変更に注意してください。

data Req = Single Course
    | Any [Req]
    | All [Req]
    deriving Show

こっちも一緒。

satisfies :: [Course] -> Req -> Bool

タイプを[コース]から[コース]に変更しました。

course1 = Course 1 "One"
course2 = Course 2 "Two"
course3 = Course 3 "Three"
course4 = Course 4 "Four"
course5 = Course 5 "Five"

req1 = Single course2
req2 = Any [Single course2, Single course3, Single course5]
req3 = All [Single course1, Single course2]
req4 = Any [req2, req3]
req5 = All [req4, req1]

いくつかのテストデータ。

satisfies cs (Single c) = c `elem` cs

シングルコースの要件に一致します。他の2つは、そのシンプルさが美しいです。彼らが行うことのほとんどは、プレリュードですでに定義されており、英語のように読むことができます。

satisfies cs (Single c) = c `elem` cs
satisfies cs (Any reqs) = any (satisfies cs) reqs
satisfies cs (All reqs) = all (satisfies cs) reqs

これがあなたの友達の型署名ですanyそしてall

any :: (a -> Bool) -> [a] -> Bool
all :: (a -> Bool) -> [a] -> Bool

どちらもブール関数を取り、リストの各メンバーに対してテストします。要件のリストと、テスト機能(satisfies再帰的に使用され、部分的に免除されたコースに適用されたもの)があるので、それらを直接使用できます。

テストしてみましょう:

*TestSO15213421> satisfies [course1] req1
False
*TestSO15213421> satisfies [course2] req1
True
*TestSO15213421> satisfies [course1, course2] req1
True
*TestSO15213421> satisfies [course1, course2] req1
True
*TestSO15213421> satisfies [course1, course2] req3
True
*TestSO15213421> satisfies [course1, course3] req3
False
*TestSO15213421> satisfies [course1, course3] req2
True
*TestSO15213421> satisfies [course4] req2
False
*TestSO15213421> satisfies [course4] req5
False
*TestSO15213421> satisfies [course5] req2
True
*TestSO15213421> satisfies [course4] req4
False
*TestSO15213421> satisfies [course2] req4
True
*TestSO15213421> satisfies [course2, course3] req4
True
*TestSO15213421> satisfies [course5, course3] req4
True
*TestSO15213421> satisfies [course5, course3] req5
False

すべて期待通り。

于 2013-03-05T14:22:37.483 に答える
3

さて、私はあなたが望むものはを取り入れることであるReqと仮定し、それからそれに応じて、与えられたリストがそれをCourses満たすかどうかを決定します。

次に、これをはるかに苦痛の少ないものにするために1つの変更を加えます。

Req = ... Any [Courses] | All [Courses] ...

sの代わりに[Req]、実際には、任意にネストされた要件があるため、この関数を処理するのは少し不安定で奇妙です。

これを行うために、いくつかのパターンマッチングを行います。

satisfies :: [Courses] -> Req -> Bool
satisfies courses (Single course) = undefined
satisfies courses (Any reqs)      = undefined
satisfies courses (All reqs)      = undefined

さて、これで3つの問題が発生しました。

まず、リストに要素が含まれているかどうかを確認するにはどうすればよいですか?これを行う方法を理解させましょう。elem次に関数を理解するとします。

satisfies courses (Single course) = course `elem` courses

次に、2つのリストが交差しているかどうかを確認するにはどうすればよいですか?関数がinter

satisfies courses (Any reqs)      = courses `inter` reqs

そして最後に、リストに別のリストが含まれているかどうかをどのように確認しますか?あれを呼べcontains

satisfies courses (All reqs0)      = courses `contains` reqs

現在、これはADTを処理するためのかなり一般的な方法です。それらを分解し、ケースバイケース分析のようなものを実行します。

于 2013-03-05T00:22:48.060 に答える