Imagesharp mutate in F# - f#

I am trying to use ImageSharp to edit pictures in F#. I'm struggling to get the image mutations working
To do an image mutation in C#, it looks like you just use the mutate method and a lambda:
image.Mutate(x => x.Kodachrome())
Normally, to change C# lambdas to F#, I would just use anonymous functions, like so:
image.Mutate(fun x -> x.Kodachrome())
When I do so, I get the following error:
No overloads match for method 'Mutate'. The available overloads are shown below (or in the Error List window).
It looks like the Mutate method takes an ImageProcessor, but for some reason in F# the compiler can't figure out that the anonymous function is an ImageProcessor. How can I get an image mutation to work in F#?

F# can automatically convert from an anonymous function (fun ...) to a System.Action<_>, but only if the types match exactly. Here, they don't, because Kodachrome() doesn't return unit. So you need to ignore its return value:
image.Mutate(fun x -> x.Kodachrome() |> ignore)

You will need to convert your F# lambda into an Action explicitly:
image.Mutate <| Action<_> (fun x -> x.Kodachrome ())

Related

F#: How exactly is ToString supposed to be used?

I am learning F# but I just don't understand how I am supposed to use ToString. Below are a few attempts. The syntax errors are saying it is expecting type string but that it is actually type uint -> string. So it doens't actually appear to be invoking a function? Could this be explained? This seems like such a simple thing to do but I can't figure it out.
open System
open System.IO
open FSharp.Data
[<EntryPoint>]
let main (args: string[]) =
let htmlPage = HtmlDocument.Load("https://scrapethissite.com/")
printfn "%s" htmlPage.ToString // This causes a syntax error
htmlPage.ToString
|> (fun x -> printfn "%s" x) // This also causes a syntax error
0
.ToString is a method, not a value. In F# every method and every function has a parameter. In fact, that's how functions differ from values (and methods from properties): by having a parameter.
Unlike in C#, F# methods and functions cannot be parameterless. If there is nothing meaningful that you'd want to pass to the method, that method would still have one parameter of type unit. See how this is visible in the error message? unit -> string is the type.
To call such method, you have to pass it the parameter. The sole value of type unit is denoted (). So to call the method you should do:
htmlPage.ToString ()
|> printfn "%s"
Your first example is a bit more complicated. The following would not work:
printfn "%s" htmlPage.ToString ()
Why? Because according to F# syntax this looks like calling printfn and passing it three parameters: first "%s", then htmlPage.ToString, and finally (). To get the correct order of calls you have to use parentheses:
printfn "%s" (htmlPage.ToString ())
And finally, general piece of advice: when possible try to avoid methods and classes in F# code. Most things can be done with functions. In this particular case, the ToString methods can be replaced with the equivalent function string:
printfn "%s" (string htmlPage)

Why does F# require type placeholders for ToDictionary?

given
[
1,"test2"
3,"test"
]
|> dict
// turn it into keyvaluepair sequence
|> Seq.map id
|> fun x -> x.ToDictionary<_,_,_>((fun x -> x.Key), fun x -> x.Value)
which fails to compile if I don't explicitly use the <_,_,_> after ToDictionary.
Intellisense works just fine, but compilation fails with the error: Lookup on object of indeterminate type based on information prior to this program point
So, it seems, Intellisense knows how to resolve the method call.
This seems to be a clue
|> fun x -> x.ToDictionary<_,_>((fun x -> x.Key), fun x -> x.Value)
fails with
Type constraint mismatch.
The type 'b -> 'c is not compatible with type IEqualityComparer<'a>
The type 'b -> 'c' is not compatible with the type 'IEqualityComparer<'a>'
(using external F# compiler)
x.ToDictionary((fun x -> x.Key), id)
works as expected as does
let vMap (item:KeyValuePair<_,_>) = item.Value
x.ToDictionary((fun x -> x.Key), vMap)
I've replicated the behavior in FSI and LinqPad.
As a big fan of and avid reader of Eric Lippert I really want to know
what overload resolution, (or possibly extension methods from different places) are conflicting here that the compiler is confused by?
Even though the types are known ahead, the compiler's getting confused between the overload which takes an element selector and a comparer. The lambda compiles to FSharpFunc rather than the standard delegate types in C# like Action or Func, and issues do come up translating from one to the other. To make it work, you can :
Supply a type annotation for the offending Func
fun x -> x.ToDictionary((fun pair -> pair.Key), (fun (pair : KeyValuePair<_, _>) -> pair.Value)) //compiles
or name the argument as a hint
fun x -> x.ToDictionary((fun pair -> pair.Key), elementSelector = (fun (pair) -> pair.Value))
or force it to pick the 3 argument version:
x.ToLookup((fun pair -> pair.Key), (fun (pair) -> pair.Value), EqualityComparer.Default)
Aside
In your example,
let vMap (item:KeyValuePair<_,_>) = item.Value
x.ToDictionary((fun x -> x.Key), vMap)
you would explicitly need to annotate vMap because the compiler cannot find out what type the property exists on without another pass. For example,
List.map (fun x -> x.Length) ["one"; "two"] // this fails to compile
This is one of the reasons why the pipe operator is so useful, because it allows you to avoid type annotations:
["one"; "two"] |> List.map (fun x -> x.Length) // works
List.map (fun (x:string) -> x.Length) ["one"; "two"] //also works
The short answer:
The extension method ToDictionary is defined like this:
static member ToDictionary<'TSource,_,_>(source,_,_)
but is called like this:
source.ToDictionary<'TSource,_,_>(_,_)
The long answer:
This is the F# type signature of the function you are calling from msdn.
static member ToDictionary<'TSource, 'TKey, 'TElement> :
source:IEnumerable<'TSource> *
keySelector:Func<'TSource, 'TKey> *
elementSelector:Func<'TSource, 'TElement> -> Dictionary<'TKey, 'TElement>
But I only specified two regular parameters: keySelector and elementSelector. How come this has a source parameter?!
The source parameter is actually not put in the parenthesis, but is passed in by saying x.ToDictionary, where x is the source parameter. This is actually an example of a type extension. These kinds of methods are very natural in a functional programming language like F#, but more uncommon in an object oriented language like C#, so if you're coming from the C# world, it will be pretty confusing. Anyway, if we look at the C# header, it is a little easier to understand what is going on:
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector
)
So the method is defined with a "this" prefix on a first parameter even though it is technically static. It basically allows you to add methods to already defined classes without re-compiling or extending them. This is called prototyping. It's kinda rare if you're a C# programmer, but languages like python and javascript force you to be aware of this. Take this example from https://docs.python.org/3/tutorial/classes.html:
class Dog:
tricks = [] # mistaken use of a class variable
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks # unexpectedly shared by all dogs
['roll over', 'play dead']
The method add_trick is defined with self as a first parameter, but the function is called as d.add_trick('roll over'). F# actually does this naturally as well, but in a way that mimics the way the function is called. When you declare:
member x.doSomething() = ...
or
member this.doSomething() = ...
Here, you are adding function doSomething to the prototype (or class definition) of "x"/"this". Thus, in your example, you actually have three type parameters, and three regular parameters, but one of them is not used in the call. All you have left is to declare the key selector function, and the element selector function, which you did. That's why it looks weird.

F# standard function that invokes its argument

Probably a newbie question, but is there a standard function like
let apply f = f()
in F#?
No, there is not a standard function for this.
In most cases, just calling the function is shorter and more obvious than using apply would be, so I'm not entirely sure how this would be useful:
foo ()
apply foo
Now, you can also write application using |>, but that's not very nice either:
() |> foo
I guess the only place where apply would be useful is:
functions |> List.map apply
functions |> List.map (fun f -> f ())
Here, the version without apply is shorter, but I don't think it is worth having a named function in the library just for this one use case.
You could actually use |> here to avoid fun, which makes for a lovely piece of ASCII art :-), but not for something that I would ever want to see in my codebase:
functions |> List.map ((|>) ())

f# signature matching explained

I am running into difficulty with F# in numerous scenarios. I believe I'm not grasping some fundamental concepts. I'm hoping someone can track my reasoning and figure out the (probably many) things I'm missing.
Say I'm using Xunit. What I'd like to do is, provided two lists, apply the Assert.Equal method pairwise. For instance:
Open Xunit
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 Assert.Equal test1 test2
The compiler complains that the function Equal does not take one parameter. As far as I can tell, shouldn't map2 be providing it 2 parameters?
As a sanity check, I use the following code in f# immediate:
let doequal = fun x y -> printf "result: %b\n" (x = y)
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 doequal test1 test2;;
This seems identical. doequal is a lambda taking two generic parameters and returning unit. List.map2 hands each argument pairwise into the lambda and I get exactly what I expected as output:
result: true
result: true
result: false
So what gives? Source shows Xunit.Equal has signature public static void Equal<T>(T expected, T actual). Why won't my parameters map right over the method signature?
EDIT ONE
I thought two variables x and y vs a tuple (x, y) could construct and deconstruct interchangeably. So I tried two options and got different results. It seems the second may be further along than the first.
List.map2 Assert.Equal(test1, test2)
The compiler now complains that 'Successive arguments should be separated spaces or tupled'
List.map2(Assert.Equal(test1, test2))
The compiler now complains that 'A unique overload method could not be determined... A type annotation may be needed'
I think that part of the problem comes from mixing methods (OO style) and functions (FP style).
FP style functions have multiple parameters separated by spaces.
OO style methods have parens and parameters separated by commas.
Methods in other .NET libraries are always called using "tuple" syntax (actually subtly different from tuples though) and a tuple is considered to be one parameter.
The F# compiler tries to handle both approaches, but needs some help occasionally.
One approach is to "wrap" the OO method with an FP function.
// wrap method call with function
let assertEqual x y = Assert.Equal(x,y)
// all FP-style functions
List.map2 assertEqual test1 test2
If you don't create a helper function, you will often need to convert multiple function parameters to one tuple when calling a method "inline" with a lambda:
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2
When you mix methods and functions in one line, you often get the "Successive arguments should be separated" error.
printfn "%s" "hello".ToUpper()
// Error: Successive arguments should be separated
// by spaces or tupled
That's telling you that the compiler is having problems and needs some help!
You can solve this with extra parens around the method call:
printfn "%s" ("hello".ToUpper()) // ok
Or sometimes, with a reverse pipe:
printfn "%s" <| "hello".ToUpper() // ok
The wrapping approach is often worth doing anyway so that you can swap the parameters to make it more suitable for partial application:
// wrap method call with function AND swap params
let contains searchFor (s:string) = s.Contains(searchFor)
// all FP-style functions
["a"; "b"; "c"]
|> List.filter (contains "a")
Note that in the last line I had to use parens to give precedence to contains "a" over List.filter
public static void Equal<T>(T expected, T actual)
doesn't take two parameters - it takes one parameter, which is a tuple with two elements: (T expected, T actual).
Try this instead:
List.map2 Assert.Equal(test1, test2)
It's all there in the type signatures.
The signature for Assert.Equals is something along the lines of 'a * 'a -> unit. List.map2 expects a 'a -> 'b -> 'c.
They just don't fit together.
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2 - works because the lambda wrapping Equals has the expected signature.
List.zip test1 test2 |> List.map Assert.Equal - works because you now have a single list of tuples, and since List.map wants an 'a -> 'b function (where 'a is now a tuple), Assert.Equal is now fair game.
It's simply not true that two values and a tuple are implicitly interchangeable. At least not as far as F# the language is concerned, or the underlying IL representation is concerned. You can think that it's that way when you call into F# code from, say, C# - an 'a -> 'b -> 'c function there is indeed called the same way syntactically as an 'a * 'b -> 'c function - but this is more of an exception than a rule.
According to its signature Xunit.Assert.Equal() takes a single 2 values tuple parameter

Using AutoMapper with F#

I'm trying to use AutoMapper from F#, but I'm having trouble setting it up due to AutoMapper's heavy use of LINQ Expressions.
Specifically, the AutoMapper type IMappingExpression<'source, 'dest> has a method with this signature:
ForMember(destMember: Expression<Func<'dest, obj>>, memberOpts: Action<IMemberConfigurationExpression<'source>>)
This is typically used in C# like this:
Mapper.CreateMap<Post, PostsViewModel.PostSummary>()
.ForMember(x => x.Slug, o => o.MapFrom(m => SlugConverter.TitleToSlug(m.Title)))
.ForMember(x => x.Author, o => o.Ignore())
.ForMember(x => x.PublishedAt, o => o.MapFrom(m => m.PublishAt));
I made an F# wrapper that arranges things so that type inference can work. This wrapper allows me to translate the C# example above into something like this:
Mapper.CreateMap<Post, Posts.PostSummary>()
|> mapMember <# fun x -> x.Slug #> <# fun m -> SlugConverter.TitleToSlug(m.Title) #>
|> ignoreMember <# fun x -> x.Author #>
|> mapMember <# fun x -> x.PublishedAt #> <# fun m -> m.PublishAt #>
|> ignore
This code compiles, and it seems pretty clean as far as syntax and usage. However, at runtime AutoMapper tells me this:
AutoMapper.AutoMapperConfigurationException: Custom configuration for members is only supported for top-level individual members on a type.
I presume this is caused by the fact that I have to convert Expr<'a -> 'b> into Expression<Func<'a, obj>>. I convert the 'b to obj with a cast, which means my lambda expression is no longer simply a property access. I get the same error if I box the property value in the original quotation, and don't do any splicing at all inside forMember (see below). However, if I don't box the property value, I end up with Expression<Func<'a, 'b>> which does not match the parameter type that ForMember expects, Expression<Func<'a, obj>>.
I think that this would work if AutoMapper's ForMember was completely generic, but forcing the return type of the member access expression to be obj means that I can only use it in F# for properties that are already directly of type obj and not a subclass. I can always resort to using the overload of ForMember that takes the member name as a string, but I thought I'd check to see if anyone has a brilliant work-around before I give up on compile-time typo-checking.
I'm using this code (plus the LINQ part of F# PowerPack) to convert an F# quotation into a LINQ expression:
namespace Microsoft.FSharp.Quotations
module Expr =
open System
open System.Linq.Expressions
open Microsoft.FSharp.Linq.QuotationEvaluation
// http://stackoverflow.com/questions/10647198/how-to-convert-expra-b-to-expressionfunca-obj
let ToFuncExpression (expr:Expr<'a -> 'b>) =
let call = expr.ToLinqExpression() :?> MethodCallExpression
let lambda = call.Arguments.[0] :?> LambdaExpression
Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)
This is the actual F# wrapper for AutoMapper:
namespace AutoMapper
/// Functions for working with AutoMapper using F# quotations,
/// in a manner that is compatible with F# type-inference.
module AutoMap =
open System
open Microsoft.FSharp.Quotations
let forMember (destMember: Expr<'dest -> 'mbr>) (memberOpts: IMemberConfigurationExpression<'source> -> unit) (map: IMappingExpression<'source, 'dest>) =
map.ForMember(Expr.ToFuncExpression <# fun dest -> ((%destMember) dest) :> obj #>, memberOpts)
let mapMember destMember (sourceMap:Expr<'source -> 'mapped>) =
forMember destMember (fun o -> o.MapFrom(Expr.ToFuncExpression sourceMap))
let ignoreMember destMember =
forMember destMember (fun o -> o.Ignore())
Update:
I was able to use Tomas's sample code to write this function, which produces an expression that AutoMapper is satisfied with for the first argument to IMappingExpression.ForMember.
let toAutoMapperGet (expr:Expr<'a -> 'b>) =
match expr with
| Patterns.Lambda(v, body) ->
// Build LINQ style lambda expression
let bodyExpr = Expression.Convert(translateSimpleExpr body, typeof<obj>)
let paramExpr = Expression.Parameter(v.Type, v.Name)
Expression.Lambda<Func<'a, obj>>(bodyExpr, paramExpr)
| _ -> failwith "not supported"
I still need the PowerPack LINQ support to implement my mapMember function, but they both work now.
If anyone is interested, they can find the full code here.
Now that F# is happy to generate a Expression<Func<...>> directly from a fun expression, this is relatively easy to solve. The biggest problem now is that the F# compiler seems to get confused by the overloading of the ForMember method, and is unable to infer correctly what you want. This can be circumvented by defining an extension method with a different name:
type AutoMapper.IMappingExpression<'TSource, 'TDestination> with
// The overloads in AutoMapper's ForMember method seem to confuse
// F#'s type inference, forcing you to supply explicit type annotations
// for pretty much everything to get it to compile. By simply supplying
// a different name,
member this.ForMemberFs<'TMember>
(destGetter:Expression<Func<'TDestination, 'TMember>>,
sourceGetter:Action<IMemberConfigurationExpression<'TSource, 'TDestination, 'TMember>>) =
this.ForMember(destGetter, sourceGetter)
You can then use the ForMemberFs method more or less as the original ForMember is intended to work, e.g.:
this.CreateMap<Post, Posts.PostSummary>()
.ForMemberFs
((fun d -> d.Slug),
(fun opts -> opts.MapFrom(fun m -> SlugConverter.TitleToSlug(m.Title)))
I'm not quite sure how to fix the generated expression tree (that's doable by post-processing it, but it is pain to find out what AutoMapper expects). However, there are two alternatives:
As a first option - the expressions that you need to translate are fairly simple. They are mostly just method calls, property getters and uses of a variable. This means that it should be possible to write your own quotation to expression trees translator that produces exactly the code you want (then you can also add your own handling of obj, perhaps by calling Expression.Convert to build the expression tree). I wrote a simple quotation tranlsator as a sample, which should handle most of the stuff in your sample.
As a second option - if AutoMapper provides an option to specify just a property name - you could just use quotations of the form <# x.FooBar #>. These should be quite easy to deconstruct using the Patterns.PropertyGet pattern. The API should maybe look like this:
Mapper.CreateMap<Post, Posts.PostSummary>(fun post summary mapper ->
mapper |> mapMember <# post.Slug #> // not sure what the second argument should be?
|> ignoreMember <# post.Author #> )
Or, in fact, you could use this style of API even in the first case, because you don't need to write lambda expressions repeatedly for every single mapping, so maybe it is a bit nicer :-)

Resources