0

I'm trying to build a list in OCaml that takes its end range variable from a function which returns an int cast from a float:

    #require "batteries"
    #require "pa_comprehension"
    #require "core_kernel"
open Batteries
open Core_kernel

let factor_of num fact = num mod fact == 0 ;;

let limit num =  Float.to_int (floor (sqrt num) ) ;;

the population of this list is not performed due to:

Error: This expression has type int but an expression was expected of type [<Downto | To ]

in both the (yummy) batteries list comprehension:

[? List: x | x <- 0--(limit num) ; factor_of num x ?] ;;

and the (slightly less but still quite readable) core_kernel List constructor:

List.(range 0 (limit num) |> filter ~f:( fun x -> factor_of num x) );;

I'm thinking that the return from limit num is trapped inside the (evil) monad that provides the Float.to_int function. This also happens when using Float.int_of_float, the type signatures are the same:

utop # Float.to_int;;
- : float -> int = <fun>

So... how do I get my int 'out' of the monad, or, if this is not the problem, what is going on and how do I cast to an actual int that is usable in this way?

Also, could someone point me to a decent 'What the hell are these things: Monads' tutorial for tiny, tiny brains? I am at my wits end with them.

UPDATE: The error was not caused by any monadic behaviour (or use at all, in fact) it was due to the incorrect use of an infix operator (mod) and a couple of other quirks in functional thinking that I have not completely understood. I'm not sure this post should still exist but maybe it is an example of the mistakes you can make when moving into the functional paradigm...?

MarkJL
  • 485
  • 1
  • 9
  • 17
  • 1
    I would say you need to get your number not into a monad, but into the right type, maybe just add the constructor? Your example is not runnable, and syntax extensions and liberal use of Open tends to obfuscate the code IMO. – Str. Oct 12 '15 at 12:26
  • I know it's not runnable, I am trying to get it to run. Yes, I would like to cast a float to an int but I am not sure how in OCaml. The way I have used is documented here: http://stackoverflow.com/questions/7868424/cast-float-to-int-in-ocaml?rq=1 and I can find no other way to do it. I'm not sure what you mean by obfuscation in this case... Are you discouraging the use of libraries? – MarkJL Oct 12 '15 at 12:31
  • After considering your comment I have discovered what is wrong, thank you Str! If you answer the question I can upvote it :) The problem was not what I thought it was. It was due to the use of the mod operator incorrectly and passing an int to the sqrt function. (I had to cast that to a float). You were right in that you made me think about the error differently. – MarkJL Oct 12 '15 at 12:48
  • 1
    Pleased to help, and good luck with OCaml. Not enough stuff to write an answer. And monads have been explained a hundred times, still someone has to do it the easy way... – Str. Oct 12 '15 at 16:56
  • They have been, unfortunately all in the same way with increasing stress on how 'not scary' they are ;) I'll keep searching for a good one and put the address here when I find it. Maybe this post will end up being useful for something. – MarkJL Oct 12 '15 at 17:55
  • 1
    The arg of limit is a float ; but in the same expression it shall be an int due to factor_of. And secondly, List.(range 0 (limit num)) is missing one arg, it should be List.(range 0 `To (limit num)) (assuming limit takes an int as input) – Pierre G. Oct 13 '15 at 18:39

1 Answers1

0

I have managed to get to the source of the problem. Over thinking and a late night:

The error was not caused by any monadic behaviour (or use of monads at all, in fact) it was due to the incorrect use of an infix operator (mod) and a couple of other quirks in functional thinking that I have not completely understood. I'm not sure this post should still exist but maybe it is an example of the mistakes you can make when moving into the functional paradigm...?

Credit to helping me fix the issue to Str for helping me bend my mind. Joe Gob has also pointed out the main issue in the code. More casting between float and int based of the types required by my functions.

This is the corrected code (deps.ml is a requirements file):

   #use "deps.ml";;
open Batteries
open Core_kernel

let factor_of num fact = num mod fact == 0 ;;

let limit num = 2 * Float.to_int (floor (sqrt num)) ;;

let factor_list_of num =
  [? List: x | x <- 1--(limit (Int.to_float num)) ; factor_of num x ?]

let sum_factors num = ( List.fold_right (+) (factor_list_of num) 0 )

let is_perfect num = sum_factors num == num
let is_abundant num = sum_factors num > num
let is_deficient num = sum_factors num < num

Basically I have been spoiled by Ruby, but I strongly advise rubyists to take up ocaml, it's has the closest style to ruby code of the functional languages.

MarkJL
  • 485
  • 1
  • 9
  • 17