2

Can I apply a list of n values to a function that takes n values, where n varies?

A first naive attempt is the following but the compiler (fairly) complains of a weird self-referential type for applyN

applyN f xs =
    case xs of
        [] -> f
        (x::xs) -> applyN (f x) xs

I can't see how a fold would work and respect its type signature either.

For context, I want to take a list of N Json Decoders and evaluate

Json.objectN ConstructorN n1 n2 ... nN

Clearly if n is known (let's say 2) then we have

case lst of
    (d1 :: d2 :: _) -> Json.object2 Constructor2 d1 d2
    otherwise -> ....

but that's a lot of code to write if I cannot generalise for n.

I'm fearing it is not possible as in Haskell it needs some special compiler flags.

Community
  • 1
  • 1
Simon H
  • 20,332
  • 14
  • 71
  • 128
  • You are returning a function? [] -> f. That seems odd to me, but I honestly don't know. – mac10688 Dec 07 '15 at 16:35
  • Yeah. ApplyN is all wrong. But I need a suggestion – Simon H Dec 07 '15 at 16:36
  • So you are trying to perform a fold. What do you want the return type to be in the function? A list of things, or some type? By the way, I don't know Elm and I'm in the middle of learning Haskell. Bare with me if I'm way off base. – mac10688 Dec 07 '15 at 16:38
  • I know if you want to return a list, it's easy to return an empty list on the base case. But if you are trying to build up one object, it escapes me what you should do. What if your base case matched on one item instead of an empty list? Like so, [x::[]] -> f x – mac10688 Dec 07 '15 at 16:41
  • You also mentioned fold, but I think a fold needs to have an accumulator. That's why it's hard to find out what you want to return for the base case. A fold would match on the empty list and return the accumulator. – mac10688 Dec 07 '15 at 19:35

2 Answers2

2

No, you can not do that, at least not without dependant types or at least some type level trickery, which there is none of in Elm (for reference: How do I define Lisp’s apply in Haskell?)

(This is why there are all the objectN functions by the way.)

Try to restructure your code - can't f just take a list?

Community
  • 1
  • 1
Philip Kamenarsky
  • 2,757
  • 2
  • 24
  • 30
1

In this context of Json decoding, if you have a list literal with decoders, you can do something equivalent to applyN. This pattern uses the functions map: (a -> b) -> Decoder a -> Decoder b and andMap : Decoder (a -> b) -> Decoder a -> Decoder b. You use it like so:

Constructor
  `Json.map` n1
  `Json.andMap` n2
  `Json.andMap` ...
  `Json.andMap` nN

Sadly andMap isn't offered for every core module. You can define it yourself if there is a map2 or andThen. In this case object2 works, it's basically the same as map2. So:

andMap : Decoder (a -> b) -> Decoder a -> Decoder b
andMap decFun decA =
  object2 (\f a -> f a) decFun decA

You can also use Json.Decode.Extra.apply, which is the same thing, just named in a non-standard way*.

*non-standard within the Elm world anyway

Apanatshka
  • 5,958
  • 27
  • 38
  • OMG: use the fact that parsers are applicative. Unutterably clever – Simon H Dec 10 '15 at 10:48
  • Would this work for TupleX - I think not as Tuple checks the length of the array immediately, so you can't incrementally work over it? – Simon H Dec 12 '15 at 16:01