2012-05-04 21 views
17

Tôi biết rằng Haskell củaScala tương đương do-ký hiệu của Haskell (một lần nữa)

do 
    x <- [1, 2, 3] 
    y <- [7, 8, 9] 
    let z = (x + y) 
    return z 

thể được thể hiện trong Scala như

for { 
    x <- List(1, 2, 3) 
    y <- List(7, 8, 9) 
    z = x + y 
} yield z 

Nhưng, đặc biệt là với monads, Haskell thường có câu lệnh bên trong do khối không tương ứng với <- hoặc =. Ví dụ, đây là một số mã từ Pandoc sử dụng Parsec để phân tích cú pháp một cái gì đó từ một chuỗi.

-- | Parse contents of 'str' using 'parser' and return result. 
parseFromString :: GenParser tok st a -> [tok] -> GenParser tok st a 
parseFromString parser str = do 
    oldPos <- getPosition 
    oldInput <- getInput 
    setInput str 
    result <- parser 
    setInput oldInput 
    setPosition oldPos 
    return result 

Như bạn có thể thấy, nó lưu vị trí và đầu vào, chạy phân tích cú pháp trên chuỗi, và sau đó phục hồi các đầu vào và vị trí trước khi trở về kết quả.

Tôi không thể cho cuộc sống của tôi tìm ra cách dịch setInput str, setInput oldInputsetPosition oldPos vào Scala. Tôi nghĩ rằng nó sẽ làm việc nếu tôi chỉ cần đặt biến điều vô lý trong vì vậy tôi có thể sử dụng <-, như

for { 
    oldPos <- getPosition 
    oldInput <- getInput 
    whyAmIHere <- setInput str 
    result <- parser 
    ... 
} yield result 

nhưng tôi không chắc chắn đó là trường hợp, và nếu nó là đúng, tôi chắc chắn rằng phải có một cách tốt hơn để làm điều này. Ồ, và nếu bạn có thể trả lời câu hỏi này, bạn có thể trả lời thêm một câu hỏi nữa không: tôi phải nhìn chằm chằm vào Monads bao lâu trước khi họ không cảm thấy như ma thuật đen? :-)

Cảm ơn! Todd

+7

Nếu bạn không dùng quy mô để sử dụng biến, bạn có thể thay thế tên bằng dấu gạch dưới: '_ <- setInput str' – incrop

+0

Tôi đoán đó là cách giống như Scala nhất để làm điều đó. – TOB

+0

Không chắc chắn nó sẽ thực sự có thể, nhưng điều này có thể trông tự nhiên hơn bằng cách di chuyển các phát biểu này vào phần thân của for, nơi bạn thực sự có thể đi theo kiểu thủ tục. – dividebyzero

Trả lời

24

Có, bản dịch đó hợp lệ.

do { x <- m; n } tương đương với m >>= \x -> ndo { m; n } tương đương với m >> n. Vì m >> n được định nghĩa là m >>= \_ -> n (trong đó _ có nghĩa là "không ràng buộc giá trị này với bất kỳ thứ gì"), đó thực sự là bản dịch hợp lệ; do { m; n } giống với do { _ <- m; n } hoặc do { unusedVariable <- m; n }.

Tuyên bố không có liên kết biến trong khối do chỉ đơn giản là bỏ qua kết quả, thường là do không có kết quả có ý nghĩa. Ví dụ, không có gì thú vị để làm với kết quả của putStrLn "Hello, world!", vì vậy bạn sẽ không ràng buộc kết quả của nó với một biến.

(Đối với các monads là ma thuật đen, nhận thức tốt nhất bạn có thể có là chúng không thực sự phức tạp chút nào; cố gắng tìm ý nghĩa sâu hơn trong chúng thường không phải là cách hiệu quả để học cách chúng hoạt động. Tôi khuyên bạn nên đọc Typeclassopedia để hiểu rõ về kiểu chữ trừu tượng của Haskell, mặc dù bạn sẽ cần phải đọc phần giới thiệu chung của Haskell để tận dụng nó.)

+1

Bất kỳ ý tưởng nào tại sao Scala không cung cấp đường cho '>>'? –

+0

Tôi nghĩ vì scala cung cấp một sự hiểu biết đơn lẻ dưới dạng cho. Có lẽ thứ tự tính toán không được duy trì. Chỉnh sửa: Không bao giờ nhớ nó dường như được duy trì. –

+1

Câu trả lời trên Monad thực sự tốt. Nó chỉ là một mô hình lập trình. Không có gì nhiều "ma thuật đen". –

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