2017-12-05 24 views
5

Xin chào những người bán hàng rong.Các cách để áp dụng hàm functor nhiều lần

Giả sử tôi có một hàm ứng dụng (không phải là một thể hiện đơn lẻ) I muốn áp dụng nhiều lần cho một giá trị ban đầu thuần túy. Ví dụ,

λ> Just (1+) <*> (Just (1+) <*> pure 0) 
Just 2 

Nếu tôi muốn khái quát này cho bất kỳ số ứng dụng liên tiếp, tôi có thể làm điều đó với một fold.

applyAppl :: Applicative f => f (a -> a) -> Int -> f a -> f a 
applyAppl f n i = foldr (<*>) i $ replicate n f 

Sau khi định nghĩa này,

λ> applyAppl (Just (1+)) 10 $ pure 0 
Just 10 

Tôi có một nghi ngờ vụng về rằng tổng quát cũng có thể là thực hiện với một trong những bậc cao được xây dựng trong các công cụ applicative như sequenceA hoặc traverse. Có thể không?

(. Edited để đưa vào tài khoản hai bình luận đầu tiên dưới đây)

+2

Bạn có thể cung cấp loại chức năng bạn đang cố gắng viết không? –

+0

Bạn có ý nghĩa gì bởi "dễ dàng hơn"? Hàm của bạn là một dòng mã duy nhất; nó không thực sự dễ dàng hơn thế. – user2407038

+0

việc đơn giản hóa bạn muốn làm là gì? Tôi đã cố gắng nghĩ về một cái gì đó, nhưng nó thực sự đã kết thúc được một số loại gấp, và bạn phải gọi '<*> 'để kéo chức năng từ applicative ra được một chức năng trong hask. – HuStmpHrrr

Trả lời

3

Bạn có thể sử dụng iterate:

applyAppl :: Applicative f => f (a -> a) -> Int -> f a -> f a 
applyAppl f n i = iterate (f <*>) i !! n 

Loaded vào GHCi:

ghci> applyAppl (Just (+1)) 10 (pure 0) 
Just 10 

Tôi không chắc đó là nhất thiết phải tốt hơn việc triển khai của bạn, vì tôi nghi ngờ cả hai triển khai hợp nhất thành một thứ gì đó về cơ bản cùng một hồ sơ hiệu suất (mặc dù tôi chưa thử nghiệm), nhưng nó khác.

Tôi đã thấy loại hình "iterate với (!!)" này để ghi nhớ vì vậy tôi khá chắc chắn rằng, ít nhất, nó sẽ không có hiệu suất kém hơn.

+0

Đã cải thiện, nhưng vẫn yêu cầu tôi cung cấp '(<*>)' một cách rõ ràng, trong trường hợp này là 'lặp lại'. Chỉ cần cố gắng hiểu cách máy móc ứng dụng có thể được sử dụng để giải quyết trực tiếp điều này. – jhu

+0

@jhu Tôi khá chắc chắn rằng không có gì được xây dựng để tránh điều đó. Tôi có thể sai (đặc biệt là lúc 2:35 sáng nay, hah), nhưng tôi không thể nghĩ ra bất cứ điều gì vào lúc này. Hàm dựng sẵn Các hàm ứng dụng mà tôi có thể nghĩ ngay bây giờ, không ai trong số chúng có "trạng thái" cần thiết (theo cách bạn cần): chúng không theo dõi các kết quả trung gian theo bất kỳ cách nào.Vì vậy, ví dụ, một cái gì đó như '(trình tự (chuỗi fmap (replicateM 10 (Chỉ cần (+1)))) 0' sẽ chỉ cung cấp cho bạn' Chỉ cần [1,1,1,1,1,1,1,1 , 1,1] '. –

0

Có lẽ bạn đang tìm kiếm sự thay đổi sau câu trả lời @ David Young:

foo :: Applicative f => f (a -> a) -> Int -> a -> f a 
foo f n i = fmap (($ i) . iterateN n) f 
    where iterateN n f = (!! n) . iterate f 

hiến:

> foo (Just (1+)) 10 0 
Just 10 
> 

này sử dụng "máy móc applicative" trong hình thức thể hiện functor cho applicatives để thực hiện cả lặp lại chức năng và ứng dụng mà không sử dụng rõ ràng <*>. Tôi không chắc bạn muốn gì ở đây nữa.

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