2010-07-09 57 views
6

Trong một số previous question Tôi được cho biết cách viết lại biểu thức tính toán của mình để nó sử dụng đệ quy đuôi. Tôi viết lại mã của tôi nhưng vẫn có một StackOverflowException. Để xác định vị trí các vấn đề tôi đã viết một số mã nhỏ sử dụng một đơn nguyên nhà nước (lấy từ this blog entry):Biểu thức tính toán đệ quy

type State<'a, 's> = State of ('s -> 'a * 's) 

let runState (State s) initialState = s initialState 

let getState = State (fun s -> (s,s)) 
let putState s = State (fun _ -> ((),s)) 

type StateBuilder() = 
    member this.Return a = State (fun s -> (a, s)) 
    member this.Bind(m, k) = 
    State (fun s -> let (a,s') = runState m s in runState (k a) s') 
    member this.ReturnFrom a = a 
let state = new StateBuilder() 

let s max = 
    let rec Loop acc = state { 
     let! n = getState 
     do! putState (n + 1) 
     if acc < max then 
      return! Loop (acc + 1) 
     else return acc 
     } 
    Loop 0 

runState (s 100000) 0 

này được ném một StackOverflowException một lần nữa, mặc dù chức năng Vòng có thể sử dụng đuôi đệ quy (?). Tôi đoán có điều gì đó sai với lớp StateBuilder. Tôi đã cố gắng làm điều gì đó với phương thức Delay. Bọc tất cả mọi thứ trong một lambda thêm, mà không thành công. Im hoàn toàn bị mắc kẹt vào lúc này. Dưới đây nỗ lực thứ hai của tôi (không biên dịch):

type State<'a, 's> = State of ('s -> 'a * 's) 

let runState (State s) initialState = s initialState 

let getState = fun() -> State (fun s -> (s,s)) 
let putState s = fun() -> State (fun _ -> ((),s)) 

type StateBuilder() = 
    member this.Delay(f) = fun() -> f() 
    member this.Return a = State (fun s -> (a, s)) 
    member this.Bind(m, k) = 
    fun() -> State (fun s -> let (a,s') = runState (m()) s in runState ((k a)()) s') 
    member this.ReturnFrom a = a 
let state = new StateBuilder() 

let s max = 
    let rec Loop acc = state { 
     let! n = getState 
     do! putState (n + 1 - acc) 
     if acc < max then 
      return! Loop (acc + 2) 
     else return acc 
     } 
    Loop 0 

runState (s 100000()) 0 

Trả lời

14

Tôi sợ rằng bạn có thể nhận được StackOverflowException bởi vì bạn đang chạy chương trình trong chế độ Debug với người khuyết tật thế hệ đuôi gọi. Nếu bạn truy cập thuộc tính Project, bạn có thể tìm thấy hộp kiểm Tạo cuộc gọi đuôi trên tab Xây dựng. Khi tôi tạo một dự án mới, tôi có thể tái tạo hành vi, nhưng sau khi kiểm tra tùy chọn này, nó hoạt động tốt (ngay cả đối với số lần lặp lại lớn hơn nhiều).

Lý do tại sao cuộc gọi đuôi bị tắt theo mặc định trong chế độ Gỡ lỗi là nó làm cho việc gỡ lỗi trở nên khó khăn hơn (nếu cuộc gọi được thực hiện dưới dạng cuộc gọi đuôi, bạn sẽ không thấy cuộc gọi đó trong Ngăn xếp cuộc gọi cửa sổ)

Đây sẽ là lý do khá ngớ ngẩn cho lỗi ... xin lỗi vì tôi quên đề cập đến điều này khi bạn hỏi trước đó!

+0

Thật dễ dàng, khi bạn thực sự biết điều đó: D Cảm ơn bạn! Bây giờ nó đang làm việc. – PetPaulsen

Các vấn đề liên quan