2012-04-20 18 views
27

Tôi đã đọc về functors ứng dụng, đáng chú ý là trong Functional Pearl của McBride và Paterson. Nhưng tôi muốn củng cố sự hiểu biết của mình bằng cách thực hiện một số bài tập. Tôi thích các bài tập lập trình hơn nhưng các bài tập bằng chứng cũng được chấp nhận. Bài tập nào sẽ giúp tôi học lập trình hiệu quả với các ứng viên functors?Nơi để tìm các bài tập lập trình cho các ứng viên functors?

Bài tập cá nhân là OK làm chỉ dẫn cho các bài tập được liệt kê ở nơi khác.

+3

Tôi không thể đề xuất bài tập, nhưng bạn có thể xem xét các ứng viên không đơn thuần (một câu hỏi quan trọng có vẻ là "tại sao thiết kế một hàm functor khi nó ít mạnh hơn một đơn?"). Ứng dụng đa lỗi (trong Paterson và McBride) là một, cũng có các trình phân tích cú pháp của Doaitse Swierstra, một hoạt ảnh _Active_ trong Andy Gill và Bảng đen của Kevin Matledge và tôi nghĩ rằng Andy Gill và đồng nghiệp của Kansas 'Lava dựa trên một hàm functor. –

Trả lời

20

Có vẻ như thú vị khi đăng một số câu hỏi làm câu trả lời. Đây là một điều thú vị, về sự tương tác giữa ApplicativeTraversable, dựa trên sudoku.

(1) Xem xét

data Triple a = Tr a a a 

Xây dựng

instance Applicative Triple 
instance Traversable Triple 

để các dụ Applicative làm "vector" và dụ Traversable làm việc trái sang phải. Đừng quên xây dựng một ví dụ phù hợp Functor: kiểm tra xem bạn có thể trích xuất mẫu này từ một trong các ví dụ Applicative hoặc Traversable không. Bạn có thể tìm thấy

hữu ích cho trường hợp sau.

(2) Xem xét

newtype (:.) f g x = Comp {comp :: f (g x)} 

Chứng minh rằng

instance (Applicative f, Applicative g) => Applicative (f :. g) 
instance (Traversable f, Traversable g) => Traversable (f :. g) 

Bây giờ xác định

type Zone = Triple :. Triple 

Giả sử chúng tôi đại diện một Board như một khu vực dọc các khu ngang

type Board = Zone :. Zone 

Hiển thị cách sắp xếp lại vị trí đó dưới dạng vùng ngang của các khu vực dọc và làm hình vuông của hình vuông, sử dụng chức năng của traverse.

(3) Xem xét

newtype Parse x = Parser {parse :: String -> [(x, String)]} deriving Monoid 

hoặc một số công trình khác phù hợp (lưu ý rằng hành vi thư viện Monoid cho | Có lẽ | là không phù hợp).Xây dựng

instance Applicative Parse 
instance Alternative Parse -- just follow the `Monoid` 

và thực hiện

ch :: (Char -> Bool) -> Parse Char 

trong đó tiêu thụ và cung cấp một nhân vật nếu nó được chấp nhận bởi một vị nhất định.

(4) Thực hiện một phân tích cú pháp trong đó tiêu thụ bất kỳ số lượng khoảng trắng, tiếp theo là một chữ số duy nhất (0 đại diện cho khoảng trống)

square :: Parse Int 

Sử dụng puretraverse để xây dựng

board :: Parse (Board Int) 

(5) Hãy xem xét các functors không đổi

newtype K a x = K {unK :: a} 

và constru ct

instance Monoid a => Applicative (K a) 

sau đó sử dụng để thực hiện traverse

crush :: (Traversable f, Monoid b) => (a -> b) -> f a -> b 

Xây dựng newtype wrappers cho Bool thể hiện cấu trúc monoid nối tiếp và rời rạc của nó. Sử dụng crush để triển khai các phiên bản anyall hoạt động với bất kỳ Traversable functor nào.

(6) Thực hiện

duplicates :: (Traversable f, Eq a) => f a -> [a] 

máy tính danh sách các giá trị mà xảy ra nhiều hơn một lần. (Không hoàn toàn tầm thường.) (Có một cách đáng yêu để làm điều này bằng phép tính khác biệt, nhưng đó là một câu chuyện khác.)

(7) Thực hiện

complete :: Board Int -> Bool 
ok :: Board Int -> Bool 

đó kiểm tra xem một bảng là (1) đầy đủ chỉ các số trong [1..9] và (2) không có các bản sao trong bất kỳ hàng, cột hoặc ô nào.

+0

Bài tập tuyệt vời! – luqui

5

Khám phá Typeclassopedia. Nó đi kèm với một lời giải thích tốt từ mặt đất lên và một số bài tập trên đường đi.

4
+0

Liên kết này có vẻ đã chết, nhưng [đây là trang tại Máy Wayback lưu trữ trên Internet] (https://web.archive.org/web/*/http://www.cis.upenn.edu/~cis194/lectures/ *): [Functors] (https://web.archive.org/web/20130803145920/http://www.cis.upenn.edu/~cis194/lectures/09-functors.html); [Thư viện ứng tuyển] (https://web.archive.org/web/20130803134207/http://www.cis.upenn.edu/~cis194/lectures/10-applicative.html) –

12

Một cách tuyệt vời để thực hành là sử dụng Parsec trong một applicative chứ không phải là một phong cách monadic. Hầu hết các trình phân tích cú pháp hoàn toàn là ứng dụng, do đó bạn không cần phải sử dụng ký hiệu do bao giờ hết.

Ví dụ: cho các biểu thức:

import qualified Text.Parsec as P 
import qualified Text.Parsec.Token as P 
import Control.Applicative 

data Expr = Number Int | Plus Expr Expr 

lex = P.makeTokenParser ... -- language config 

expr = number <|> plus 
    where 
    number = Number <$> P.integer lex 
    plus = Plus <$> number <* P.symbol lex "+" <*> expr 
+0

Tôi tò mò- -Bạn có thể đưa ra một số ví dụ phổ biến hoặc ít nhất là hợp lý mà bạn * không thể * phân tích cú pháp với một functor ứng dụng nhưng có thể với một đơn nguyên không? –

+7

@TikhonJelvis, * chính thức * chúng tương đương với sức mạnh, ít nhất là trên một bảng chữ cái hữu hạn, nhưng theo kiểu bệnh lý (cả hai đều hỗ trợ các ngữ pháp vô hạn). Nhưng một ví dụ tốt về nơi bạn sẽ (hợp lý) cần một đơn nguyên sẽ là nếu bạn có một ngôn ngữ có thể định nghĩa các cấu trúc ngữ pháp mới cần được xem xét sau này trong phân tích cú pháp.'Applicative' không thể thay đổi cấu trúc * của nó * dựa trên nội dung * của nó *,' Monad' có thể. – luqui

+0

+1 Khi tôi thấy tiêu đề, tôi cũng nghĩ ngay về Parsec. Đó là một cách tuyệt vời để thực hành giải quyết các vấn đề thú vị, không tầm thường, nhưng đơn giản. –

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