2012-07-29 36 views
25

Tôi đã chán một ngày và muốn tập thể dục bộ não của mình, vì vậy tôi quyết định thực hiện 99 Haskell Problems nhưng hạn chế bản thân để làm chúng theo kiểu không có điểm. Một vấn đề mà dường như cắt lên rất nhiều khi tôi đang làm những việc theo kiểu không điểm là: Làm thế nào để bạn áp dụng nhiều hàm cho cùng một giá trị trong khi vẫn giữ mỗi kết quả như một thực thể độc lập? Sử dụng ký hiệu nhọn:Áp dụng nhiều chức năng cho cùng một kiểu điểm không có giá trị trong Haskell

foobar x = [id x, reverse x] 

Và những gì tôi đã đưa ra cho đến nay trong ký hiệu điểm miễn phí:

foobar' = `map` [id, reverse] ($ x) 

tôi dường như không thể nhận được rằng x ra khỏi cuối của đó.

Trả lời

25

Những người khác đã đăng tải cách bạn có thể làm điều này bằng cách sử dụng Reader đơn nguyên, nhưng đó không phải là cách duy nhất. Nó chỉ ra rằng chức năng thứ hai của bạn là khá gần. Tôi nghĩ bạn có nghĩa là đăng bài

foobar' x = (`map` [id, reverse]) ($ x) 

Kể từ khi x đã ở gần vị trí ngoài cùng bên phải, bạn sắp hoàn tất.Thứ nhất, chuyển đổi phần ($ x) vào một chức năng, bởi vì đó là một chút dễ dàng hơn để làm việc với:

-- by the definition of a right operator section 
foobar'2 x = (`map` [id, reverse]) (\y -> ($) y x) 

Tiếp theo tháo x khỏi cơ thể lambda bằng cách đưa một biến mới vào phạm vi, và áp dụng các chức năng để x

-- lambda abstraction I think... 
foobar'2 x = (`map` [id, reverse]) $ (\z y -> ($) y z) x 

Viết lại ứng dụng này như một hàm hợp, và sau đó bạn eta có thể giảm:

-- by definition of '.' 
foobar'3 x = (`map` [id, reverse]) . (\z y -> ($) y z) $ x 

-- eta reduction 
foobar'4 = (`map` [id, reverse]) . (\z y -> ($) y z) 

Cuối cùng, hãy lưu ý rằng chúng tôi có thể thay thế lambda bằng một hàm

-- by definition of `flip` 
foobar'5 = (`map` [id,reverse]) . flip ($) 

và bạn có biểu mẫu không có điểm.

8

Bạn sẽ được quan tâm trong Applicative thể hiện của các đơn nguyên đọc:

instance Applicative (e ->) 

Sử dụng nó, bạn có thể dễ dàng phân phối một cuộc tranh cãi:

liftA2 (+) sin cos 3 

Đây sincos là chức năng, mà cả hai nhận giá trị 3. Các kết quả riêng lẻ sau đó được kết hợp sử dụng (+). Bạn có thể kết hợp điều này với ví dụ Category của (->), nhưng các phiên bản chuyên biệt của phiên bản (.)id đã được xác định trong Prelude.

Bối cảnh: Các Applicative dụ cho (e ->) thực sự đại diện cho tính toán SKI, nơi (<*>)S combinator và pureK combinator. S được sử dụng một cách chính xác để phân phối một cuộc tranh cãi với hai chức năng:

S f g x = f x (g x) 

Phải mất một ứng dụng chức năng (fg) và làm cho cả phụ thuộc vào giá trị x ((fx) (gx)).

9

Sử dụng sequence:

> let foobar' = sequence [id, reverse] 
> foobar' "abcde" 
["abcde","edcba"] 
+0

Chỉ khi bạn ok với những hạn chế. Điều này sẽ không hoạt động cho tất cả các công dụng. –

+0

@ ThomasM.DuBuisson: những hạn chế nào? –

+0

@BenMillwood Tôi đang đề cập đến các ràng buộc về kiểu chữ. Câu trả lời của JohnL là kiểu 'a -> [a]'. Câu trả lời này, trong khi tốt đẹp và sạch sẽ, là loại 'Monad ((-> a) => a -> [a]'. –

5

Có một vài bộ kết hợp thành ngữ cơ bản bật lên liên tục và được triển khai lại với nhiều khái niệm và thư viện khác nhau, nhưng về cơ bản thì rất đơn giản. Tên có thể thay đổi, và một số thực hiện được trong điều kiện của người khác:

fork (f,g) x = (f x, g x)    -- == (f &&& g) 
prod (f,g) x = (f $ fst x, g $ snd x) -- == (f *** g) 
pmap f (x,y) = (f x, f y)    -- == (f *** f) 
dup  x = (x,x) 

vv Tất nhiên uncurry f (x,y) == f x y được sử dụng rất nhiều với những, quá.

&&&*** được xác định trong Control.Arrow, cũng như firstsecond. Sau đó prod (f,id) == first f, prod(id,g) == second g vv vv

Vì vậy, bạn foobar trở thành

foobar = (\(a,b)->[a,b]) . fork (id,reverse) 
     = (\(a,b)->[a,b]) . (id &&& reverse) 
     = (\(a,b)->[a,b]) . (id *** reverse) . dup 
     = join $ curry ((\(a,b)->[a,b]) . second reverse) 

Đối với người cuối cùng bạn cũng cần phải nhập Control.MonadControl.Monad.Instances. Xem thêm this question.


cuối chỉnh sửa: cũng có, sử dụng Control.Applicative như gợi ý trong câu trả lời của ertes,

 = (:) <*> ((:[]) . reverse) 
+0

cũng,' (:) <*> (tinh khiết. ngược lại) '(' ((->) r), [ ] 'Các ứng dụng),' ([id, đảo ngược] <*>). Pure' ('[]' Áp dụng), 'chuỗi [id, đảo ngược]' ('((->) r)' Monad). –

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