Callum Linington
Callum Linington

Reputation: 14417

make printfn more clear in a function pipeline

So I have this last piece in a pipe

|> Array.iter (fun name -> name 
                                |> transform 
                                |> printfn "RENAME '%s' INTO '%s'" name )

The transform is:

let transform (text: string) = 
    text.Replace(" ", ".")

To me the iter predicate function isn't very clear, it is saying push name into transform then push the result in printfn with the original name appended to it....

Is there a way to make the transformation pipe more intention revealing using pipe forward or backward operators.

I thought maybe

name
  |> printfn "RENAME '%S' INTO '%S'"
  <| transform

But obviously that doesn't work.

If it can't look nicer in the pipe then I guess it is the most succinct way - apart from making a a new function that combines the printfn in some fashion with the transform, but I wouldn't mind avoiding that...

I just want to make sure I'm not missing any straightforward syntax..

I don't think there is, because I'm facing a function that takes multiple arguments, in order to use it in a pipe forward it can only have 1 parameter, which is effectively what I'm doing by partial application.

Upvotes: 1

Views: 105

Answers (3)

Helge Rene Urholm
Helge Rene Urholm

Reputation: 1188

This is kind of how I would go about this task:

let array = [|
    "one"
    "two"
    "three"
|]


let transform s = s, s + "_transformed"

let printIt (n,t) =  printfn "RENAME '%s' INTO '%s'" n t 


array
|> Array.map transform
|> Array.iter printIt

My "best practice" tells me that I always should create and use functions. This way the flow (map and iter) is constant, and the functions or data may change.

Addendum to "clarify" WHY to use functions and what not

let myPipeLineWithPrint t p a=
    a
    |> Array.map t
    |> Array.iter p

//"Old" Version With above data
myPipeLineWithPrint transform printIt array


type SomeRecord = {
    Name: string
    MoreStuff: string
}

type OtherRecord = {
    NewName: string
    OldName: string
}


let array2 = [|
    {Name="one"; MoreStuff="dontcare"}
    {Name="two"; MoreStuff="dontcare"}
    {Name="three"; MoreStuff="dontcare"}
|] 

let transform2 {Name=n; MoreStuff=ms} = transform n

myPipeLineWithPrint transform2 printIt array2


let transform3 {Name=n; MoreStuff=_} =
    let (_,nn) = transform n
    {NewName= nn; OldName=n}

let printIt2 {NewName=nn; OldName = o} = printfn "RENAME '%s' INTO '%s'" o nn   

myPipeLineWithPrint transform3 printIt2 array2

Upvotes: 1

Bartek Kobyłecki
Bartek Kobyłecki

Reputation: 2395

Sometimes it is better to avoid unnecessary piping as it can obfuscate the code. Your function simply prints as follows:

printfn "RENAME '%s' INTO '%s'" name (transform name)

And you can omit parens by using <|:

printfn "RENAME '%s' INTO '%s'" name <| transform name

And that looks better IMHO.

Upvotes: 4

monoceres
monoceres

Reputation: 4770

Maybe skipping the pipe is more clear in this case?

|> Array.iter (fun name -> printfn "RENAME '%s' INTO '%s'" name (transform name))

Also note that your original predicate can be composed further like so:

|> Array.iter (transform >> printfn "RENAME '%s' INTO '%s'" name)

Which can be written like this if you want the transform to come last:

|> Array.iter ((printfn "RENAME '%s' INTO '%s'" name) << transform)

Upvotes: 2

Related Questions