Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to partially apply nth parameter in Haskell?

I am curious if it is possible to write a function apply_nth that takes a function, the number of a parameter, and that parameter's value and then returns a new, partially-applied function.

The feeling I get is that this is impossible due to the type system, but I can't come up with a satisfying answer. I also can't come up with a working type signature.

If the language were more loosely-typed, I imagine the code might look like this.

apply_nth f 0 x = f x
apply_nth f n x = \a -> apply_nth (f a) (n-1) x

Any ideas?

like image 636
danmcardle Avatar asked Oct 22 '15 21:10

danmcardle


1 Answers

Not that weird type families, but not super nice either:

{-# LANGUAGE GADTs, DataKinds, TypeFamilies, TypeOperators #-}

import Data.Proxy

type family Fun as b where
    Fun '[]       b = b
    Fun (a ': as) b = a -> Fun as b

data SL as where
    Sn :: SL '[]
    Sc :: SL as -> SL (a ': as)

applyN :: Proxy c -> SL as -> Fun as (b -> c) -> b -> Fun as c
applyN p  Sn    f y = f y
applyN p (Sc s) f y = \x -> applyN p s (f x) y

main = print $ applyN Proxy (Sc (Sc Sn)) zipWith [1,2,3] (-) [6,5,4] -- [5,3,1]

We can also package Proxy c into SL:

data SL as c where
    Sn :: SL '[] c
    Sc :: SL as c -> SL (a ': as) c

applyN :: SL as c -> Fun as (b -> c) -> b -> Fun as c
applyN  Sn    f y = f y
applyN (Sc s) f y = \x -> applyN s (f x) y

main = print $ applyN (Sc (Sc Sn)) zipWith [1,2,3] (-) [6,5,4] -- [5,3,1]

Or you can simply define a few combinators:

z = id
s r f y x = r (f x) y
applyN = id

main = print $ applyN (s (s z)) zipWith [1,2,3] (-) [6,5,4] -- [5,3,1]
like image 59
user3237465 Avatar answered Nov 16 '22 23:11

user3237465