Как часть проекта, я назначил себя как способ улучшить свои знания о F # и функциональном программировании в целом, я пытаюсь написать алгоритм сопоставления строк с нуля без использования каких-либо петель или переменных (или регулярных выражений, или String.Replace и друзей). Поскольку это чисто учебный проект, меня не интересует наилучший способ сделать это, просто лучший функциональный способ сделать это.F # String Pattern-Matching with Wildcards
Я пытаюсь написать функцию, которая принимает подстановочный знак, строку шаблона и строку ввода в качестве параметров. Если шаблон не соответствует входу, функция возвращает None
. Если шаблон соответствует вводу, функция возвращает Some(str)
, где str
- это какая-либо часть входной строки, сопоставляемая с любыми подстановочными знаками, которые могли присутствовать в строке шаблона.
У меня это в основном работает, и я включу код в одно мгновение. Я написал общую функцию сопоставления шаблонов, которая работает в любом общем списке всего, что поддерживает равенство, а затем вспомогательную функцию, которая берет строки и передает списки символов в общую функцию. Все это работает, за исключением одного: поддержка нескольких подстановочных знаков в строке шаблона не очень хороша - она принимает совпадения для каждого шаблона и объединяет их вместе в одну строку на выходе.
Например:
> strMatch '*' "foo" "bar";;
val it : string option = None
> strMatch '*' "test" "test";;
val it : string option = Some ""
> strMatch '*' "functional programming is *" "functional programming is fun";;
val it : string option = Some "fun"
> strMatch '*' "* and *" "you and me";;
val it : string option = Some "youme"
Это последний один, что я пытаюсь исправить. В идеале я хотел бы вернуть список строк, а не одну строку, причем каждый элемент в списке является строкой, которая соответствует одному шаблону. В противном случае я, вероятно, поразмышляю с версией, которая возвращает только совпадение для первого подстановочного знака - это конкатенированные значения из обоих типов, от которых мне нужно избавиться. Я просто не совсем уверен, как подойти к нему.
Так что, если кто-нибудь может предложить, как я могу сгруппировать свои возвращаемые значения, с помощью которых они будут совпадать, я был бы благодарен. Я также заинтересован в любых других улучшениях в моем коде, которые вы могли бы предложить.
let rec doMatch (wildcard:'a) (pat:'a list) (input:'a list) : 'a list option =
let singleMatch p i =
match (p, i) with
| phd :: ptl, ihd :: itl ->
if phd = wildcard then
match doMatch wildcard ptl itl with
| None -> None
| Some x -> Some(ihd :: x)
else None
| _ -> None
let longerMatch p i =
match (p, i) with
| phd :: ptl, ihd :: itl ->
if phd = wildcard then
match doMatch wildcard p itl with
| None -> None
| Some x -> Some(ihd :: x)
else None
| _ -> None
match (pat, input) with
| [], [] -> Some([])
| [], _::_ -> None
| _::_, [] -> None
| phd :: ptl, ihd :: itl ->
if phd <> wildcard then
if phd = ihd then doMatch wildcard ptl itl
else None
else
match singleMatch pat input with
| Some x -> Some(x)
| None -> longerMatch pat input
let strMatch (wildcard:char) (pat:string) (input:string) =
match doMatch wildcard (List.ofSeq pat) (List.ofSeq input) with
| None -> None
| Some x -> Some(new string(Array.ofList x))
Вы, наверное, догадались, но это часть реализации чата-робота Eliza в F #.
Я согласен, это в значительной степени именно то, что я хочу в конечном итоге. Я думал, это то, о чем я просил, но, может быть, я не был ясен. Мой более глубокий вопрос просто: «Как мне туда добраться?» Я довольно новичок в F #, и я все время теряюсь во всех рекурсиях и списках, и еще много раз, когда я пытаюсь реализовать его, как вы предлагаете. –
Кроме того, поскольку моя универсальная функция doMatch уже возвращает параметр «списка», мне не нужно будет вместо этого возвращать опцию списка «list list»? Моя проблема в том, что мне не ясно, как сказать, когда я должен добавить текущий сопоставленный символ в существующий список символов и начать новый список символов. –
После редактирования: Большое спасибо. 'Some (x :: xs) -> Some ((ihd :: x) :: xs)' был бит синтаксиса, который я просто не получал. Сегодня я чему-то научился! –