Tôi có thể làm gì với callCC mà không thể thực hiện được với cont?


9

Tôi thực sự đang vật lộn với việc hiểu callCC. Tôi có được sức mạnh của Continuations và tôi đã sử dụng khái niệm này trong một số dự án của mình để tạo ra các khái niệm hay. Nhưng tôi chưa bao giờ cần phải sử dụng thứ gì đó có khả năng lớn hơn cont :: ((a->r)->r)-> Cont r a.

Sau khi sử dụng nó, rất có lý do tại sao họ gọi Cont Monad là mẹ của tất cả các đơn vị, YET, tôi không nhận được khi nào tôi cần sử dụng callCC, và đó chính xác là câu hỏi của tôi.


Bạn đã sử dụng Contnhư thế nào? Khi bạn nói rằng bạn không cần phải sử dụng thứ gì đó mạnh hơn cont, điều đó có nghĩa là bạn chưa sử dụng resethay shiftlà gì?
KA Buhr

Tôi đã không sử dụng resethoặc shift. Tôi đã sử dụng nó để xác định một ngôn ngữ bị bỏ qua có thể bị đình chỉ cho đến khi một hành động nhất định được giải quyết bằng một quy trình khác, và sau đó nó tiếp tục với "tiếp tục" đã cho. Có thể tôi cho cảm giác có nhiều trải nghiệm với Cont Monad, nhưng thực sự không nhiều, tôi chỉ thực sự muốn hiểu callCC
Alejandro Navas

Câu trả lời:


10

callCC cung cấp cho bạn ngữ nghĩa "trở về sớm", nhưng trong một bối cảnh đơn điệu.

Giả sử bạn muốn doOnevà nếu điều đó quay trở lại True, bạn lập tức dừng lại, nếu không, bạn tiếp tục doTwodoThree:

doOne :: Cont r Bool
doTwo :: Cont r ()
doThree :: Cont r ()

doThings :: Cont r ()
doThings = do
    one <- doOne
    if one
        then pure ()
        else do
            doTwo
            doThree

Thấy ifphân nhánh đó không? Một nhánh không tệ lắm, có thể bị xử lý, nhưng hãy tưởng tượng có nhiều điểm như vậy mà bạn chỉ muốn bảo lãnh? Điều này trở nên rất xấu xí rất nhanh chóng.

Với callCCbạn có thể có "trở về sớm": bạn bảo lãnh tại điểm phân nhánh và không phải lồng phần còn lại của tính toán:

doThings = callCC \ret -> do
    one <- doOne
    when one $ ret ()
    doTwo
    doThree

Dễ chịu hơn nhiều để đọc!

Quan trọng hơn, vì retở đây không phải là một cú pháp đặc biệt (như returntrong các ngôn ngữ giống như C), mà chỉ là một giá trị như bất kỳ ngôn ngữ nào khác, bạn cũng có thể chuyển nó sang các chức năng khác! Và các hàm đó sau đó có thể thực hiện cái được gọi là "trả lại không cục bộ" - tức là chúng có thể "dừng" doThingstính toán, thậm chí từ nhiều cuộc gọi lồng nhau sâu. Ví dụ: tôi có thể kiểm tra doOnekết quả của một hàm riêng biệt checkOnenhư thế này:

checkOne ret = do
    one <- doOne
    when one $ ret ()

doThings = callCC \ret -> do
    checkOne ret
    doTwo
    doThree

Tôi hiểu rồi! và bvề cơ bản chỉ là một ký tự đại diện để bạn có thể xâu chuỗi nhiều phần tiếp theo bên trong callCC. Dù sao, một khi retđược áp dụng, phần tiếp theo được tạo ra bởi lệnh gọi cc sẽ "trả lại" bất cứ thứ gì được đưa vào ret. Điều đó khá phức tạp, nhưng khá thông minh, nhưng vô cùng mạnh mẽ Tôi thấy không có nhiều nơi sử dụng sức mạnh như vậy không giống như giết một con ruồi bằng nuke
Alejandro Navas

1
@caeus Vui mừng tôi có thể giúp. Nếu bạn thích câu trả lời của tôi, bạn sẽ xem xét chấp nhận nó?
Fyodor Soikin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.