OCaml开发问题:fold检查单词存在及提取子词时的类型错误排查
Hey there! Let's work through your two OCaml tasks and fix that confusing error you're seeing. First, let's break down the error message you got:
Error: This variant expression is expected to have type unit The constructor :: does not belong to type unit
This usually happens when you're using a function that expects a unit return type (like List.iter) but accidentally return a list (using :: to construct it) instead. Or, if you messed up type consistency in a fold—like starting with a boolean accumulator but trying to return a list from the fold function. Let's fix that as we go through your requirements.
1. Check if a Word Exists in a List Using Fold
We can use List.fold_left here, where our accumulator is a boolean tracking whether we've found the target word yet. The fold function will update this accumulator: if we hit the target word, we flip the accumulator to true (and it stays true for all subsequent elements).
let word_exists target_word word_list = List.fold_left (fun acc current_word -> acc || current_word = target_word) false (* Initial accumulator: start with "not found" *) word_list
Example Usage:
word_exists "hank" ["hank"; "bank"; "rank"];; (* Returns true *) word_exists "zank" ["hank"; "bank"; "rank"];; (* Returns false *)
2. Extract Valid 4-Letter Substrings from 6-Letter Words & Filter Valid 6-Letter Words
Let's break this into steps:
- First, extract all continuous 4-letter substrings from a 6-letter word (there are 3 possible substrings for any 6-letter word).
- Then, check if any of those substrings exist in your valid 4-letter word list.
- Finally, filter the list of 6-letter words to keep only those with at least one valid substring.
Step 1: Extract 4-Letter Substrings
let extract_4letter_substrings six_letter_word = if String.length six_letter_word <> 6 then [] else [ String.sub six_letter_word 0 4; (* First 4 chars: indices 0-3 *) String.sub six_letter_word 1 4; (* Chars 1-4 *) String.sub six_letter_word 2 4 ] (* Chars 2-5 *)
Step 2: Check for Valid Substrings
We'll reuse our word_exists function with a fold to check if any substring is valid:
let has_valid_substring valid_4words six_letter_word = let substrings = extract_4letter_substrings six_letter_word in List.fold_left (fun acc substr -> acc || word_exists substr valid_4words) false substrings
Step 3: Filter the 6-Letter Word List
let valid_six_letter_words valid_4words six_letter_list = List.filter (has_valid_substring valid_4words) six_letter_list
Example Usage:
let valid_4s = ["hank"; "than"; "anks"] let six_letter_candidates = ["thanks"; "banana"; "trunks"] valid_six_letter_words valid_4s six_letter_candidates;; (* Returns ["thanks"] because "thanks" has "than", "hank", "anks" — all in valid_4s *)
Why You Got That Error
Let's say you accidentally used List.iter instead of List.fold_left when checking for valid substrings, like this:
(* WRONG: List.iter expects the callback to return unit, not a list *) let wrong_check valid_4words six_letter_word = List.iter (fun substr -> if word_exists substr valid_4words then [six_letter_word] (* :: constructs a list, but unit is expected *) else ()) (extract_4letter_substrings six_letter_word)
This will trigger exactly the error you saw, because List.iter requires its callback to return unit (a "no value" type), but you're returning a list with ::. The fix is to use fold or filter instead of iter when you need to produce a value (like a boolean or a list) from your iteration.
内容的提问来源于stack exchange,提问作者John Dunn

