Есть ли способ сделать сравнение нескольких значений в строке?

Я чувствую глупость даже из-за того, что спрашиваю об этом, потому что это кажется таким тривиальным, но мой мозг подводит меня. Если бы у меня было следующее:

let a, b, c = 1, 1, 1

Есть ли подходящий способ определить, имеют ли a, b и c одинаковое значение? Что-то вроде:

let result = (a = b = c)

Это не удается, потому что выражение a = b возвращает true, а следующее выражение приводит к true = c и жалуется, что ожидал int, а не bool. Единственное, о чем я могу думать, это:

a = b && a = c && b = c

который не будет работать, когда я хочу добавить больше переменных.

На самом деле я пытаюсь сделать следующее:

let same (x: string * string * string) =
    match x with
    | (a, a, a) -> true
    | _ -> false

Я надеялся, что смогу сопоставить все элементы в одном элементе, и если бы они были разными, он бы продолжал, но на втором элементе в совпадении говорится, что он уже связан.

4 ответа

Решение

Чтобы проверить, все ли значения в списке одинаковы:

let rec same = function
  | x::y::_ when x <> y -> false
  | _::xs -> same xs
  | [] -> true

использование

let a, b, c = 1, 1, 1
same [a; b; c] //true
let same (a, b, c) = a = b && b = c

Я бы попытался использовать функцию Форалла, чтобы определить, все ли числа одинаковы.

let list = [a; b; c;];;
List.forall (fun n -> n = a) list;;
val it : bool = true

Это решение создает именно необходимый синтаксис. Удивительно для себя, довольно быстро. Кроме того, это, кажется, хороший пример использования монад, также известных как Вычислительные выражения.

// Generic
let inline mOp1<'a> op sample x = op sample x, sample
let inline mOp2<'a> op1 op2 (b, sample) x = op1 b (op2 sample x), sample

// Implementation for (=) and (&&)
let (==) = mOp1 (=)
let (&=) = mOp2 (&&) (=)

// Use
let ret1 = a == b &= c &= d &= e |> fst

Как это устроено

Подход очень упрощенная государственная монада. Монадический тип - это кортеж (bool, 'T), Первый компонент - это логическое значение текущих вычислений, а второй - примерное значение для сравнения.

(==) инициализирует монаду, похожую на Delay оператор.
(&=) используется для всех последующих сравнений. Это похоже на Bind оператор.
Нам не нужны Return так как fst будет служить довольно хорошо.
mOp1 а также mOp2 являются абстракциями над логическими операциями. Это позволяет определять ваших собственных операторов. Вот примеры or-equal а также and-greater-than:

let (|=) = mOp2 (||) (=)
let (.>) = mOp1 (>)
let (&>) = mOp2 (&&) (>)
// Use
let ret2 = a == b |= c |= d |= e |> fst // if any of b,c,d,e equals to a
let ret3 = 5 .> 3 &> 4 |> fst // true: 5>3 && 5>4
let ret4 = 5 .> 3 &> 8 &> 4 |> fst // false

Спектакль

Я действительно наслаждался прекрасным решением @ildjarn, но List довольно медленный, поэтому моя главная цель была производительность.
Выполнение цепочки из 8 сравнений, 10 миллионов раз:

  • 04972ms a=b && a=с && ...
  • 23138ms List-основан
  • 12367мс монадический
Другие вопросы по тегам