ocaml


Too eager infering of ocaml optional function argument


Consider this code:
let myFun
?(f: ('a -> int) = (fun x -> x))
(x: 'a)
: int =
f x
Looks i can't call with another argument other than int. When I try to with this code:
let usage = myFun ~f:String.length "abcdef"
Ocaml emits this error message:
Error: This expression has type string -> int
but an expression was expected of type int -> int
Type string is not compatible with type int
Looks like the inference will think 'a = int because of the default argument. It is the limitation of the language or is there a way how to write this so it compiles?
This issue is a limitation due to how optionals argument are implemented.
Essentially, function with optional argument are expanded during the type checking phase using the standard option type. For instance, your function:
let f ?(conv=(fun x -> x)) x = f x
becomes, more or less,
let f opt_conv =
let conv =
match opt_conv with
| None -> fun x -> x
| Some f -> f in
fun x -> conv x
Consequently, since the opt_conv has for type 'a->'a in the None branch, f must have for type ?conv:('a->'a) -> 'a -> 'a .
Looking at the expanded function, the problem comes from the fact that the Some branch and None should have different type to obtain your desired functionality.
For the sake of type riddles, having different types in different branch of a pattern matching is a sign that GADTs may bring a potential solution: one can define an extended option type as
type ('default,'generic) optional =
| Default: ('default,'default) optional
| Custom: 'a -> ('default,'a) optional
then it is possible to rewrite your function as
let f: type a. (int -> int, a -> int) optional -> a -> int =
fun conv x ->
match conv with
| Default -> x
| Custom f -> f x
wich leads to the expected behavior:
f Default "hi" yields a type error whereas f (Custom int_of_string) "2" returns 2.
However, without the optional argument syntactic sugar machinery, this is not really useful.
None that it is perfectly possible to extend OCaml to use the GADT-laded optional type. However this can easily lead to atrocious type errors and the corresponding increase of complexity does not make for a very attractive extension.
The notation ?(f: ('a -> int) doesn't mean that parameter f has type 'a -> int, it is a type constraint that tells the type inference algorithm, that f should be a function that returns a value of type int. The 'a here means just - "I don't care, infer it yourself". It doesn't generalize your type variable. Thus, given your constraint, the compiler infers, that (1) the type of f is int -> int (because this is the only input that satisfies your default value), (2) the type of x is also int, as you constrained it yourself (it will be inferred to the same type anyway, because of type of f.
Also, the type system here is right, by disallowing anything except int as the x parameter. Consider the following example:
myFun "hello"
According to your desire, it should be valid, but what OCaml should do in this case?
When you write
let myFun
?(f: ('a -> int) = (fun x -> x))
(x: 'a)
: int =
f x
You assert a general type but it's a mistake.
As you can see, when you interpret the function :
let myFun ?(f: ('a -> int) = (fun x -> x)) x = f x;;
val myFun : ?f:(int -> int) -> int -> int = <fun>`
Let's focus on this : f: ('a -> int) = (fun x -> x)
Here, f is, by default, a function taking x and returning x which means that the argument should have the same type as the returned value. You wrote that f is of type 'a -> int then the type of the returned value is int thus the type of the parameter is int too (and not 'a).
You can simply write : f: ('a -> 'a) = (fun x -> x) and everything will work fine.
let myFun ?(f: ('a -> 'a) = (fun x -> x)) x = f x;;
val myFun : ?f:('a -> 'a) -> 'a -> 'a = <fun>
Update
If you want your function to always return an int, you have to change the default function. For example, you can write :
let myFun ?(f: ('a -> int) = (fun _ -> 0)) x = f x;;
val myFun : ?f:('a -> int) -> 'a -> 'a = <fun>
Type inference happen at "let" level, so this kind of polymorphism is impossible.
The only way is to go is without optional argument
let myFun f x : int = f x;;
myFun id 1;;
myFun int_of_string "2";;
myFun String.length "abc";;
Where id is fun x -> x

Related Links

Indexing a set using first class module
How can I use ocamlbrowser with opam packages?
Error message “unimplemented”
ocp-indent and eliom files
How to fix the code errors in OCaml?
OCaml semicolon single expression in a for loop
How to create a module OCaml and use it?
OCaml - preprocessing with type information
OCaml type error (folding)
Unison source compile errors in OCAML
Pattern matching on string
OCaml's `type a. a t` syntax
OCaml bindings for Z3: Success in OCaml interpreter, but fail in OCaml compiler
Opaque type issue with nonrec syntax
unbound value with the out of Format.fprintf
How do you take unspecified arithmetic claim (or another function) as parameter?

Categories

HOME
jdbc
meshlab
wxwidgets
tomcat7
matplotlib
tumblr
urlencode
spring-cloud-contract
websphere-liberty
nodemailer
xcode8.3
onsen-ui2
data-synchronization
postmessage
typeahead
scala-native
netezza
sql-tuning
bar-chart
rhapsody
ada
ms-access-2007
google-api-java-client
cython
marathon
azure-servicebus-queues
auditing
pipelinedb
visual-c++-2017
mayavi
mangodb
bitcoin-testnet
ioc-container
idl
recurrence-relation
nunit-3.0
office365connectors
dql
active-model-serializers
common.logging
wcf-security
onbackpressed
xbim
bing-translator-api
3scale
startapp
lumen-5.3
timesten
livefyre
mouseclick-event
xmgrace
ruby-on-rails-2
google-maps-ios
mcrypt
fedora20
bettercms
laravel-query-builder
spark-cassandra-connector
qregexp
soda
date-format
django-south
except
insert-into
unity5.3
textkit
built-in
achartengine
twitter-rest-api
lines-of-code
ember-cli-addons
client-side-validation
inputaccessoryview
errorprovider
ghostdoc
java-collections-api
facebook-wall
humanizer
dache
smartystreets
sgml
magic-numbers
help-viewer
nservicebus4
entity-framework-4.1
pep8
zend-lucene
snapjs
javascriptserializer
tfs-power-tools
caliper
rose-db-object
expression-evaluation
hibernate3
concurrent-programming
selectmanycheckbox
charts4j
msbuildextensionpack
camtasia
savestate
microsoft.ink
inline-if
hardware-infrastructure

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App