2010-11-21 25 views
6

Bạn có thể chuyển đổihình thức Point-miễn phí so với phong cách

-- tupleUnfold :: forall a. ((forall b. a -> b)) -> a -> ((b)) 
tupleUnfold :: Int -> ExpQ 
tupleUnfold n = do 
    xs <- forM [1 .. n] (const . newName $ "x") 
    y <- newName "y" 
    let y' = varE y 
     g (ps', es') x = (varP x : ps', appE (varE x) y' : es') 
     (ps, es) = foldl' g ([], []) xs 
    lamE [tupP ps, varP y] (tupE es) 

để pointfree phong cách trong khi duy trì sự rõ ràng (tôi biết chương trình 'pointfree', nhưng không muốn xáo trộn mã thậm chí nhiều hơn)?

Dù bằng cách nào, những thay đổi nào có thể được thực hiện để cải thiện phong cách của chức năng hoặc làm cho mục đích của nó rõ ràng hơn? Chức năng này được thiết kế để sử dụng như dưới đây.

$(tupleUnfold 3) ((+ 1), (+ 2), (+ 3)) 2 
-- (3, 4, 5) 

Quy ước đặt tên tốt hơn để sử dụng (xem các biến ps, ps ', es và es') là gì?

Trả lời

5

Đây là những gì tôi có. Cần Control.Arrow (&&&)Control.Applicative (<$>).

Không thể cắt giảm nhiều hơn nữa mà không làm cho nó hoàn toàn khó hiểu.

EDIT Mặc dù không có điểm, đây là rõ ràng nhất Tôi có thể thực hiện. Cần Data.Function (on)

tupleUnfold :: Int -> ExpQ 
tupleUnfold n = do 
    y <- newName "y" 
    xs <- replicateM n (newName "x") 
    let exps = tupE $ zipWith appVars xs (repeat y) 
     pats = tupP $ map varP xs 
    lamE [pats, varP y] exps 
    where 
    appVars = appE `on` varE 
+0

Tôi thích việc sử dụng "replicateM" - không chắc chắn làm thế nào tôi bỏ lỡ một số – ScootyPuff

+0

Tôi đánh dấu câu trả lời này là câu trả lời đúng một cách tùy ý. Mặc dù cái kia là vô nghĩa ở cấp cao nhất, nhưng điều này dường như đại diện cho luồng và chuyển đổi tốt hơn - mặc dù nó hơi khó đọc hơn. – ScootyPuff

+0

Một phần lý do của nếp gấp (thay vì bản đồ) là để tránh nhiều lần di chuyển. Tôi cũng biết rằng GHC khá giỏi trong việc hợp nhất các danh sách tra cứu. Nó thường là một sự khác biệt đáng kể? Cho rằng cả hai hình thức là tương đối dễ dàng để viết, mà nên (như một quy tắc của ngón tay cái) được ưa thích? – ScootyPuff

0

Cá nhân tôi nghĩ rằng nó khá rõ ràng rồi, nhưng làm thế nào về điều này:

tupleUnfold :: Int -> ExpQ 
tupleUnfold = mapM (const . newName $ "x") . enumFromTo 1 >=> \xs -> do 
    y <- newName "y" 
    let y' = varE y 
     g (ps', es') x = (varP x : ps', appE (varE x) y' : es') 
     f ps = lamE [tupP ps, varP y] . tupE 
    uncurry f $ foldl' g ([],[]) xs 

Các Kleisli thành phần điều hành >=> (từ Control.Monad) rất hữu ích cho việc tạo ra các chức năng monadic pointfree.

+0

Tôi đã có một phiên bản đó là tại pointfree cấp cao nhất (sử dụng> =>), nhưng cuối cùng phải phá vỡ nó. Thật tốt khi biết rằng nó tương đối rõ ràng vì nó là - hầu hết những gì khiến tôi hiểu về Haskell là có bao nhiêu cách mà một thứ gì đó có thể được viết lại. – ScootyPuff

+0

Làm thế nào quan trọng là để cho bindings khi nói đến hiệu suất? Đó là lý do tại sao tôi có y '- tôi đã không chắc chắn nếu biểu thức sẽ được kéo đến một phạm vi bên ngoài. – ScootyPuff

+0

Không có tính năng y 'the 'varE y' sẽ không được chia sẻ. Nhưng tính toán đó có thể chỉ đại diện cho một nhà xây dựng, vì vậy nó không liên quan (và đừng lo lắng về hai cuộc gọi đến một nhà xây dựng so với một, đó là chỉ cho phép ngôn ngữ của bạn sở hữu - bạn sẽ không nhận được mã nhanh hơn, bạn ' sẽ chỉ nhận được mã crappy). Thủ tướng trong foldl 'là vô ích bởi vì nó là một bình thường (lười biếng) tuple. Sử dụng một tuple dữ liệu 'Tuple a b = Tuple! A! B'. Nhưng vì đây là mã giống như luồng, nên sử dụng 'foldr' - nó sử dụng ít bộ nhớ hơn. Điều này về cơ bản số tiền để 'giải nén. map' như trong phản hồi của tôi. – luqui

1

một chút khó hiểu hơn (cố gắng đọc từ phải sang trái):

tupleUnfold n = do 
    y <- newName "y" 
    uncurry lamE . ((:[varP y]) . tupP *** tupE) . unzip . 
    map (varP &&& (`appE` varE y) . varE) <$> replicateM n (newName "x") 

EDIT:
kết hợp của mũi tên và hàm hợp để chế biến

tupleUnfold n = do 
    y <- newName "y" 
    uncurry lamE . ((tupP >>> (:[varP y])) *** tupE) . unzip . 
    map (varP &&& (varE >>> (`appE` varE y))) <$> replicateM n (newName "x") 

và sử dụng hầu hết các mũi tên (chức năng xử lý đọc từ trái sang phải t)

tupleUnfold n = do 
    y <- newName "y" 
    (map (varP &&& (varE >>> (`appE` varE y))) >>> unzip >>> 
    ((tupP >>> (:[varP y])) *** tupE) >>> uncurry lamE) <$> replicateM n (newName "x") 

lưu ý rằng vào mũi tên chức năng (>>>) tương đương với lật (.)

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