Haskell递归函数开发:实现学生列表的部分科目添加功能
Alright, let's walk through how to build this recursive function for your Haskell student database. First, let's restate the requirements clearly to make sure we're on the same page:
- We need a recursive function that processes a list of
Studentrecords - When we find a student matching a specified name, we check if a target subject is not already in their liked subjects list
- If the subject isn't present, we add it to their liked subjects; if it is, we leave the student record as-is
- All other students in the list remain unchanged
First, Let's Confirm the Existing Definitions
Here's the Student data type and database you provided, formatted as code:
data Student = Student String Int [String] [String] deriving (Show, Read) db :: [Student] db = [ Student "JenDavis" 54 ["Physics", "Maths"] ["Biology", "English"], Student "BenBlue" 62 ["Art", "English"] ["Maths", "PE"], Student "JaydenBrimes" 56 ["Chemistry", "PE"] ["Music", "Maths"] ]
Step 1: Define the Function Type Signature
Our function will take three arguments: the target student's name, the subject to add, and the list of students. It will return the updated list of students. So the type signature is:
updateStudentLikes :: String -> String -> [Student] -> [Student]
Step 2: Implement the Recursive Function
We'll use standard list recursion here, with a base case for empty lists and a recursive case for processing each element:
updateStudentLikes _ _ [] = [] -- Base case: empty list stays empty updateStudentLikes targetName targetSubj (student@(Student name age liked disliked):rest) | name == targetName = if targetSubj `notElem` liked then Student name age (targetSubj : liked) disliked : updateStudentLikes targetName targetSubj rest else student : updateStudentLikes targetName targetSubj rest | otherwise = student : updateStudentLikes targetName targetSubj rest
Let's Break Down the Logic
- Base Case: If we're given an empty list of students, we just return an empty list—there's nothing to update.
- Recursive Case: We pattern match on the first student in the list (using
@to keep the fullstudentreference for later):- If the student's name matches our target name:
- Check if the target subject is not in their
likedlist usingnotElem - If it's missing, create a new
Studentrecord with the subject added to the front of thelikedlist, then recursively process the rest of the list - If the subject is already present, we keep the original student record and move on to the rest of the list
- Check if the target subject is not in their
- If the name doesn't match, we keep the original student and recursively process the remaining students
- If the student's name matches our target name:
Testing the Function
Let's test this with an example. Suppose we want to add "Maths" to BenBlue's liked subjects (since it's currently in his disliked list):
-- Call the function updatedDb = updateStudentLikes "BenBlue" "Maths" db -- Print the result main = print updatedDb
The output will show BenBlue's liked subjects now include "Maths":
[Student "JenDavis" 54 ["Physics","Maths"] ["Biology","English"],Student "BenBlue" 62 ["Maths","Art","English"] ["Maths","PE"],Student "JaydenBrimes" 56 ["Chemistry","PE"] ["Music","Maths"]]
Notes
- We're prepending the new subject to the
likedlist (usingtargetSubj : liked) because prepending is O(1) in Haskell, which is more efficient than appending. If you need the list to stay in a specific order, you could useliked ++ [targetSubj], but that's O(n) time. - The function is pure, meaning it doesn't modify the original database—it returns a new list with the updated student record. This aligns with Haskell's immutable data principles.
内容的提问来源于stack exchange,提问作者aworkinghuman

