F # - горе при заданном условии кортежа - PullRequest
0 голосов
/ 02 октября 2008

Учитывая следующее:

#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" в выражение последовательности?

Ответы [ 3 ]

1 голос
/ 02 октября 2008

Еще одно решение, которое на мой взгляд немного лучше. Он извлекает 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
1 голос
/ 02 октября 2008

Мне нравятся другие предложения о том, как потреблять "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", - это неявная информация, которая неочевидна из типа данных (вы можете продолжать вызывать ее, пока часть bool верна), что делает последовательность версия немного привлекательнее.

1 голос
/ 02 октября 2008

Это одно из решений, но я лично считаю, что это злоупотребление строительством.

#light
while 
   (let (c,x) = foo()
    if c then print_any !x
    c)
   do ()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...