Есть ли способ сделать сравнение нескольких значений в строке?
Я чувствую глупость даже из-за того, что спрашиваю об этом, потому что это кажется таким тривиальным, но мой мозг подводит меня. Если бы у меня было следующее:
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 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мс монадический