2010-03-08 33 views
10
fibs :: [Int] 
fibs = 0 : 1 : [ a + b | (a, b) <- zip fibs (tail fibs)] 

Điều này tạo ra dãy Fibonacci.Hiểu về định dạng của Haskell

Tôi hiểu hành vi của các vệ sĩ, của :, ziptail, nhưng tôi không hiểu <-. Nó làm gì ở đây?

+16

Đây không phải là biện pháp bảo vệ. Đây là danh sách hiểu. http://www.haskell.org/haskellwiki/List_comprehension – pmr

+2

Bạn có chắc đây là chuỗi Fibonacci đúng không? Yếu tố đầu tiên phải là 1 theo ý kiến ​​của tôi. – shuhalo

Trả lời

-1

Trình phân tích cú pháp sẽ biết điều gì xảy ra (a, b) nếu không?

CHỈNH SỬA: Nhờ ViralShah, tôi sẽ làm cho điều này ít gnomic hơn một chút. "< -" yêu cầu trình phân tích cú pháp gán danh sách các cặp từ phía bên phải "zip fibs (tail fibs)" sang bên trái "(a, b)".

+0

Đây là một bình luận, không phải là câu trả lời. –

1

Danh sách hiểu trong dấu ngoặc:

[ a + b | (a, b) <- zip fibs (tail fibs)] 

trả về một danh sách có chứa đầu ra (a + b), nơi các biến a và b đến từ kết quả của

zip fibs (tail fibs) 
13

Do upvotes Tôi đã bình luận của tôi thành một câu trả lời.

Những gì bạn thấy không phải là người bảo vệ nhưng là list comprehension. Để người mới bắt đầu nghĩ về nó như một cách để biểu diễn một ký hiệu toán học như A = {x | x phần tử N} có nghĩa là một cái gì đó dọc theo dòng: Tập A là tập hợp tất cả các số tự nhiên. Trong danh sách hiểu rằng sẽ là [x | x <- [1..] ].

Bạn cũng có thể sử dụng các ràng buộc đối với các số của mình: [x | x <- [1..], x `mod` 2 == 0 ] và nhiều thứ khác.

Có rất nhiều giai điệu tuyệt vời trong đó bao gồm hiểu danh sách và thậm chí là câu hỏi StackOverflow liên quan đến tài nguyên haskell.

10

Điều khó khăn duy nhất là zip fibs (tail fibs). zip chỉ cần tạo một danh sách theo cặp từ mỗi đối số của nó. Vì vậy, nếu bạn có hai danh sách như thế này:

[ 1, 2, 3, 4 ] 
[ "a", "b", "c", "d" ] 

Nén họ sẽ thực hiện:

[ (1,"a"), (2,"b"), (3,"c"), (4,"d") ] 

Các mũi tên trái (phân công vào một mô hình destructuring) chỉ trích các yếu tố kết hợp để họ có thể được thêm vào với nhau. Hai danh sách được nén là fibs(tail fibs) - nói cách khác, trình tự Fibonacci và độ lệch chuỗi Fibonacci bằng 1 phần tử. Haskell được đánh giá lười biếng, do đó, nó có thể tính toán danh sách tuy nhiên nhiều yếu tố được yêu cầu. Điều này cũng áp dụng cho zip.

+0

Hai fibs'es sẽ được đánh giá cùng một lần hoặc độc lập hai lần? –

+0

Lệnh gọi để tạo '[(1," a "," A "), (2," b "," B "), ...]' là gì? Nó vẫn là một zip? Cũng giải thích - nó hoạt động như zip trong Python, mát mẻ. – hhh

+1

@hhh hey amigo. có vẻ như bạn cần 'zip3' cho điều đó, điều này khá vui nhộn. một zip chung là dễ hiểu để thực hiện trong Haskell vì hệ thống kiểu của nó. Trong Mathematica bạn có thể làm 'Thread [{ls1, ls2, ls3}]' hoặc sử dụng 'Transpose', vv Và yea ​​Python có một lượng nhỏ các công cụ 'lập trình chức năng'. Nhưng theo như lập trình chức năng, không có ngôn ngữ nào trong số các ngôn ngữ này đến gần với các ngôn ngữ APL như J, mà là một hoặc hai bậc trên lập trình hàm và trong danh mục cao hơn của chúng. :) – amr

3

Hãy mở rộng.

zip tạo các cặp trong số hai nội dung của hai danh sách. Vì vậy, cặp đầu tiên zip fibs (tail fibs) cho chúng tôi là (0, 1), có thêm đến 1. Vì vậy, bây giờ danh sách là [0,1,1]. Bây giờ chúng ta biết ba phần tử trong danh sách, do đó, việc hiểu danh sách có thể tiếp tục, lấy mục tiếp theo từ danh sách và mục tiếp theo từ đuôi, cung cấp cho (1,1) - được thêm vào với nhau, tạo ra 2. Sau đó, chúng ta có cặp tiếp theo, (1,2), tạo số tiếp theo trong chuỗi 3. Điều này có thể tiếp tục vô hạn, vì việc hiểu sẽ luôn cung cấp đủ các mục.

1

Đối với những gì nó có giá trị, tôi tìm thấy phiên bản sau dễ hiểu:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs) 
2

Một ưu điểm của lập trình chức năng là bạn có thể đánh giá một biểu hiện bằng tay như nó là một vấn đề toán học:

fibs = 0 : 1 : [ a + b | (a, b) <- zip fibs (tail fibs)] 
    = 0 : 1 : [ a + b | (a, b) <- zip [0, 1, ??] (tail [0, 1, ??])] 

Ở đây, ?? là phần chưa được đánh giá. Chúng tôi sẽ điền vào khi chúng tôi tiến hành.

 = 0 : 1 : [ a + b | (a, b) <- zip [0, 1, ??] [1, ??])] 
    = 0 : 1 : [ a + b | (a, b) <- (0, 1) : zip [1, ??] [??]] 

Lưu ý rằng tôi eliding việc thẩm định zip từ định nghĩa của nó không được đưa ra ở đây và các chi tiết không thực sự Gecman cho câu hỏi hiện tại. Đây là ký hiệu tôi sẽ sử dụng để hiển thị mỗi cặp số được tạo bởi zip và được tiêu thụ theo danh sách hiểu.

 = 0 : 1 : 0+1 : [ a + b | (a, b) <- zip [1, ??] [??]] 
    = 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, ??] [??]] 

Bây giờ chúng ta biết rằng các phần tử tiếp theo trong ?? là một 1:

 = 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, 1, ??] [1, ??]] 
    = 0 : 1 : 1 : [ a + b | (a, b) <- (1, 1) : zip [1, ??] [??]] 
    = 0 : 1 : 1 : 1+1 : [ a + b | (a, b) <- zip [1, ??] [??]] 
    = 0 : 1 : 1 : 2 : [ a + b | (a, b) <- zip [1, ??] [??]] 

Và các yếu tố tiếp theo là 2:

 = 0 : 1 : 1 : 2 : [ a + b | (a, b) <- zip [1, 2, ??] [2, ??]] 

Rửa và lặp lại.

0

Nó định nghĩa sơ đồ dòng này

  .----->>------->>----. 
     /     \ 
     /     / 
     \     /  
    <---- 0 <---- 1 ---<<--- (+)  
       /   \   
       \    \   
        \   /  
        *---->>------*  

mà kéo đầu vào mới từ chính nó như là nó được sản xuất, nhưng luôn luôn bởi một và hai vị trí trước khi các điểm sản xuất, duy trì hai "con trỏ trở lại" vào chuỗi như nó đã là. Điều này được phản ánh trong định nghĩa fibs = 0:1:[ a+b | a <- fibs | b <- tail fibs], với sự hiểu thấu danh sách song song (:set -XParallelListComp, v.v.).

Vì nó chỉ sử dụng hai yếu tố cuối cùng của nó, nó tương đương với

map fst . iterate (\(a, b) -> (b, a+b)) $ (0,1) 
0

tôi vẫn không hiểu. tôi thích câu trả lời này: https://stackoverflow.com/a/42183415/246387 (từ code-apprentice).

nhưng tôi không hiểu tại sao từ dòng này:

= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, ??] [??]] 

nó di chuyển như sau:

= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, 1, ??] [1, ??]] 

và bên cạnh điều này, tôi có cái gì khác mà làm phiền tôi:

làm thế nào tôi có thể sử dụng fib bên trong danh sách-hiểu nếu tôi không có fib ở tất cả (vì vậy có vẻ như, nhưng chắc chắn tôi sai), bởi vì fib isn ' t tính chưa. nó "chờ đợi" (ở phía bên trái của dấu bằng) được tính ở bên phải (của dấu bằng).

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