Axarydax
Axarydax

Reputation: 16603

Append lists in F# one-liner

I'm trying to implement a RLE decoder for a game, and it works, but I'd like to shrink the code a bit, but I can't figure out how to put List.append and the repeat and rleExpand calls on one line

The signature of List.append is List.append : 'T list -> 'T list -> 'T list, so obviously I cannot just do List.append(repeat(pattern,count), rleExpand(tail,rleTag)) - but would like to know how to do that. I also can use the @ operator - maybe that's the most readable one. But how do I use List.append if my lists are created by a function application like in the listing below?

let rec repeat(item,count) = 
    match count with 
    | 0 -> []
    | n -> item :: repeat(item,n-1) 

let rec rleExpand(packed, rleTag: int) =
    match packed with
    | [] -> []    
    | tag :: count :: pattern :: tail when tag = rleTag ->
        let repeated = repeat(pattern,count)
        let rest = rleExpand(tail,rleTag)
        List.append repeated rest
    | head :: tail -> head :: rleExpand(tail,rleTag)

Upvotes: 0

Views: 720

Answers (2)

TheInnerLight
TheInnerLight

Reputation: 12184

I would probably write:

repeat(pattern,count) @ rleExpand(tail,rleTag)

But you can also write

List.append (repeat(pattern,count)) (rleExpand(tail,rleTag))

You cannot use List.append(repeat(pattern,count), rleExpand(tail,rleTag)) as you originally suggested because List.append takes curried (rather than tupled) arguments.

Upvotes: 4

Shredderroy
Shredderroy

Reputation: 2920

Does something like this work?

let repeat(item, count) = [for i in 1 .. count -> item]

let rec rleExpand(packed, rleTag: int) =
    match packed with
    | [] -> []    
    | tag :: count :: pattern :: tail when tag = rleTag ->
        List.collect id [repeat(pattern,count);  rleExpand(tail,rleTag)]
    | head :: tail -> head :: rleExpand(tail,rleTag)

It's also more commonplace to use make functions curryable by not using tuples as parameters.

Upvotes: 1

Related Questions