Более простой способ сопоставления шаблонов с началом списка в F#

Я пытаюсь написать функцию обработки строк на F#, которая выглядит так:

let rec Process html =
  match html with
  | '-' :: '-' :: '>' :: tail -> ("→" |> List.of_seq) @ Process tail
  | head :: tail -> head :: Process tail
  | [] -> []

Мое выражение сопоставления с образцом для нескольких элементов немного уродливо (вся эта штука '-' :: '-' :: '>'). Есть ли способ сделать это лучше? Кроме того, эффективно ли то, что я делаю, если мне нужно обрабатывать большие тексты? Или есть другой способ?

Пояснение: я имею в виду, например, возможность написать что-то вроде этого:

match html with
| "-->" :: tail -> 

person Dmitri Nesteruk    schedule 20.02.2009    source источник
comment
Боковое примечание: я бы использовал процесс, а не процесс - слишком большой риск конфликта пространств имен или путаницы программистов. См. этот вопрос: stackoverflow.com/questions/526930/f-naming-convention   -  person Benjol    schedule 23.02.2009
comment
Спасибо за наводку - буду иметь в виду.   -  person Dmitri Nesteruk    schedule 23.02.2009


Ответы (5)


Я согласен с другими, что использование списка символов для серьезных манипуляций со строками, вероятно, не идеально. Однако, если вы хотите продолжать использовать этот подход, один из способов получить что-то близкое к тому, что вы просите, — это определить активный шаблон. Например:

let rec (|Prefix|_|) s l =
  if s = "" then
    Some(Prefix l)
  else
    match l with
    | c::(Prefix (s.Substring(1)) xs) when c = s.[0] -> Some(Prefix xs)
    | _ -> None

Затем вы можете использовать его как:

let rec Process html =  
  match html with  
  | Prefix "-->" tail -> ("→" |> List.of_seq) @ Process tail  
  | head :: tail -> head :: Process tail  
  | [] -> []
person kvb    schedule 26.03.2009
comment
Ваши фрагменты содержат F#, который я на самом деле не понимаю :) Тогда вернитесь к книге! Спасибо! - person Dmitri Nesteruk; 26.03.2009

Есть ли способ сделать это лучше?

Конечно:

let process (s: string) = s.Replace("-->", "→")

Кроме того, эффективно ли то, что я делаю, если мне нужно обрабатывать большие тексты?

Нет, это невероятно неэффективно. Выделение памяти и сборка мусора обходятся дорого, и вы делаете это для каждого отдельного символа.

Или есть другой способ?

Попробуйте член Replace. Если это не сработает, попробуйте регулярное выражение. Если это не сработает, напишите лексер (например, используя fslex). В конечном счете, для эффективности вам нужен конечный автомат, обрабатывающий поток символов и выводящий результат путем мутации на месте.

person J D    schedule 06.08.2010
comment
Ну, я понял на собственном горьком опыте, что делать это неэффективно. Однако делать это на C# с использованием System.String и еще чего-то тоже оказалось утомительным. В конце концов, я написал DSL, который генерировал действительно злой код C++, чтобы решить эту проблему. - person Dmitri Nesteruk; 07.08.2010
comment
Да, так делают настоящие мужчины. ;-) - person J D; 07.08.2010

Я думаю, вам следует избегать использования list‹char> и использования строк и, например. String.Replace, String.Contains и т. д. System.String и System.StringBuilder гораздо лучше подходят для работы с текстом, чем list‹char>.

person Brian    schedule 20.02.2009

Для простых проблем использование String и StringBuilder напрямую, как упоминал Брайан, вероятно, лучший способ. Для решения более сложных задач вы можете воспользоваться какой-нибудь сложной библиотекой синтаксического анализа, такой как FParsec для F#.

person Tomas Petricek    schedule 20.02.2009

Этот вопрос может помочь у вас есть идеи для другого подхода к вашей проблеме - использование list‹> для содержания строк, но использование функций String в каждой строке.

person Benjol    schedule 23.02.2009