Вопрос
Учитывая следующее:
#light
//any function returning bool * 'a
let foo =
let x = ref 10
fun () ->
x := !x - 1
if !x <> 0 then
(true, x)
else
(false, x)
while let (c,x) = foo() in c do print_any x;//can't access x, but would be convinent.
//this is how I want it to work, without all the typing
let rec loop f =
match f() with
| (true, x) ->
print_any x
loop f
| (false, _) -> ()
loop foo
Как мне решить эту проблему?Или мне просто нужно пройти через преобразование «foo» в выражение последовательности?
Решение
Это одно из решений, но лично я считаю, что это злоупотребление функцией while.
#light
while
(let (c,x) = foo()
if c then print_any !x
c)
do ()
Другие советы
Еще одно решение, которое, на мой взгляд, немного лучше.Он получает x из области действия условия while и помещает его в ссылку y, которая доступна в более высокой области видимости.Все еще не лучшее (функциональное) решение, но оно работает.
let y = ref 1
while (let (c,x) = foo()
y := !x
c)
do printf "%i" !y
Я думаю, твой rec loop
Решение работает лучше всего, поскольку оно является наиболее функциональным (избегает побочных эффектов, хотя foo использует состояние) и наиболее общим (оно работает со всеми функциями одновременно с foo).Это дольше, но если вы будете использовать больше функций, таких как foo, цикл будет более продуктивным, чем одно кратчайшее решение только для foo.
Я бы даже еще больше обобщил цикл и абстрагировал действие того, что вы хотите сделать со значением в «истинной» ситуации:
let loop f a =
let rec loop2() =
match f() with
| (true, x) ->
a x
loop2()
| (false, _) -> ()
loop2()
loop foo print_any
Мне нравятся другие предложения о том, как использовать «foo», предполагая, что foo фиксирован.
На мой нос пахнет кодом «foo».Если разумно преобразовать «foo» в «bar» по примеру
let bar =
let x = ref 10
seq {
x := !x - 1
while !x <> 0 do
yield x
x := !x - 1
}
bar |> Seq.iter print_any
тогда я бы сделал это, но «бар», хотя и несколько лучше, все равно кажется подозрительным.(В «bar» я сохранил тот странный аспект, что он возвращает «int ref», а не просто «int», как это было в «foo», но, надеюсь, этот аспект был непреднамеренным?)
Я думаю, что самое интересное в "foo" - это неявная информация, которая не очевидна из типа данных (вы можете продолжать вызывать ее до тех пор, пока логическая часть верна), что делает версию seq немного более привлекательный.