Point-free in Haskell

后端 未结 5 1011
刺人心
刺人心 2020-12-14 09:30

I have this code that I want to make point-free;

(\\k t -> chr $ a + flip mod 26 (ord k + ord t -2*a))

How do I do that?

Also are the

5条回答
  •  猫巷女王i
    2020-12-14 10:04

    There's definitely a set of tricks to transforming an expression into point-free style. I don't claim to be an expert, but here are some tips.

    First, you want to isolate the function arguments in the right-most term of the expression. Your main tools here will be flip and $, using the rules:

    f a b ==> flip f b a
    f (g a) ==> f $ g a
    

    where f and g are functions, and a and b are expressions. So to start:

    (\k t -> chr $ a + flip mod 26 (ord k + ord t -2*a))
    -- replace parens with ($)
    (\k t -> chr $ (a +) . flip mod 26 $ ord k + ord t - 2*a)
    -- prefix and flip (-)
    (\k t -> chr $ (a +) . flip mod 26 $ flip (-) (2*a) $ ord k + ord t)
    -- prefix (+)
    (\k t -> chr $ (a +) . flip mod 26 $ flip (-) (2*a) $ (+) (ord k) (ord t))
    

    Now we need to get t out on the right hand side. To do this, use the rule:

    f (g a) ==> (f . g) a
    

    And so:

    -- pull the t out on the rhs
    (\k t -> chr $ (a +) . flip mod 26 $ flip (-) (2*a) $ ((+) (ord k) . ord) t)
    -- flip (.) (using a section)
    (\k t -> chr $ (a +) . flip mod 26 $ flip (-) (2*a) $ ((. ord) $ (+) (ord k)) t)
    -- pull the k out
    (\k t -> chr $ (a +) . flip mod 26 $ flip (-) (2*a) $ ((. ord) . ((+) . ord)) k t)
    

    Now, we need to turn everything to the left of k and t into one big function term, so that we have an expression of the form (\k t -> f k t). This is where things get a bit mind-bending. To start with, note that all the terms up to the last $ are functions with a single argument, so we can compose them:

    (\k t -> chr . (a +) . flip mod 26 . flip (-) (2*a) $ ((. ord) . ((+) . ord)) k t)
    

    Now, we have a function of type Char -> Char -> Int that we want to compose with a function of type Int -> Char, yielding a function of type Char -> Char -> Char. We can achieve that using the (very odd-looking) rule

    f (g a b) ==> ((f .) . g) a b
    

    That gives us:

    (\k t -> (((chr . (a +) . flip mod 26 . flip (-) (2*a)) .) . ((. ord) . ((+) . ord))) k t)
    

    Now we can just apply a beta reduction:

    ((chr . (a +) . flip mod 26) .) . (flip flip (2*a) . ((-) . ) . ((. ord) . (+) .ord))
    

提交回复
热议问题