Haskell function application and currying

后端 未结 3 654
南方客
南方客 2021-01-30 08:22

I am always interested in learning new languages, a fact that keeps me on my toes and makes me (I believe) a better programmer. My attempts at conquering Haskell come and go - t

3条回答
  •  逝去的感伤
    2021-01-30 09:11

    You're overthinking this problem. You can work it all out using simple equational reasoning. Let's try it from scratch:

    permute = foldr (concatMap . ins) [[]]
    

    This can be converted trivially to:

    permute lst = foldr (concatMap . ins) [[]] lst
    

    concatMap can be defined as:

    concatMap f lst = concat (map f lst)
    

    The way foldr works on a list is that (for instance):

    -- let lst = [x, y, z]
    foldr f init lst
    = foldr f init [x, y, z]
    = foldr f init (x : y : z : [])
    = f x (f y (f z init))
    

    So something like

    permute [1, 2, 3]
    

    becomes:

    foldr (concatMap . ins) [[]] [1, 2, 3]
    = (concatMap . ins) 1 
        ((concatMap . ins) 2
           ((concatMap . ins) 3 [[]]))
    

    Let's work through the first expression:

    (concatMap . ins) 3 [[]]
    = (\x -> concatMap (ins x)) 3 [[]]  -- definition of (.)
    = (concatMap (ins 3)) [[]]
    = concatMap (ins 3) [[]]     -- parens are unnecessary
    = concat (map (ins 3) [[]])  -- definition of concatMap
    

    Now ins 3 [] == [3], so

    map (ins 3) [[]] == (ins 3 []) : []  -- definition of map
    = [3] : []
    = [[3]]
    

    So our original expression becomes:

    foldr (concatMap . ins) [[]] [1, 2, 3]
    = (concatMap . ins) 1 
        ((concatMap . ins) 2
           ((concatMap . ins) 3 [[]]))
    = (concatMap . ins) 1 
        ((concatMap . ins) 2 [[3]]
    

    Let's work through

    (concatMap . ins) 2 [[3]]
    = (\x -> concatMap (ins x)) 2 [[3]]
    = (concatMap (ins 2)) [[3]]
    = concatMap (ins 2) [[3]]     -- parens are unnecessary
    = concat (map (ins 2) [[3]])  -- definition of concatMap
    = concat (ins 2 [3] : [])
    = concat ([[2, 3], [3, 2]] : [])
    = concat [[[2, 3], [3, 2]]]
    = [[2, 3], [3, 2]]
    

    So our original expression becomes:

    foldr (concatMap . ins) [[]] [1, 2, 3]
    = (concatMap . ins) 1 [[2, 3], [3, 2]]
    = (\x -> concatMap (ins x)) 1 [[2, 3], [3, 2]]
    = concatMap (ins 1) [[2, 3], [3, 2]]
    = concat (map (ins 1) [[2, 3], [3, 2]])
    = concat [ins 1 [2, 3], ins 1 [3, 2]] -- definition of map
    = concat [[[1, 2, 3], [2, 1, 3], [2, 3, 1]], 
              [[1, 3, 2], [3, 1, 2], [3, 2, 1]]]  -- defn of ins
    = [[1, 2, 3], [2, 1, 3], [2, 3, 1], 
       [1, 3, 2], [3, 1, 2], [3, 2, 1]]
    

    Nothing magical here. I think you may have been confused because it's easy to assume that concatMap = concat . map, but this is not the case. Similarly, it may seem like concatMap f = concat . (map f), but this isn't true either. Equational reasoning will show you why.

提交回复
热议问题