From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by sympa.inria.fr (Postfix) with ESMTPS id 8EDD6823C2 for ; Thu, 25 Jan 2018 15:04:52 +0100 (CET) Authentication-Results: mail3-smtp-sop.national.inria.fr; spf=None smtp.pra=jean-marc.alliot@irit.fr; spf=None smtp.mailfrom=jean-marc.alliot@irit.fr; spf=None smtp.helo=postmaster@sava.lunarmania.com Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of jean-marc.alliot@irit.fr) identity=pra; client-ip=67.210.109.225; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="jean-marc.alliot@irit.fr"; x-sender="jean-marc.alliot@irit.fr"; x-conformance=sidf_compatible Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of jean-marc.alliot@irit.fr) identity=mailfrom; client-ip=67.210.109.225; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="jean-marc.alliot@irit.fr"; x-sender="jean-marc.alliot@irit.fr"; x-conformance=sidf_compatible Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of postmaster@sava.lunarmania.com) identity=helo; client-ip=67.210.109.225; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="jean-marc.alliot@irit.fr"; x-sender="postmaster@sava.lunarmania.com"; x-conformance=sidf_compatible IronPort-PHdr: =?us-ascii?q?9a23=3Aji9YEBB5Lx3JMyoTzpp6UyQJP3N1i/DPJgcQr6Af?= =?us-ascii?q?oPdwSPT+p8bcNUDSrc9gkEXOFd2Cra4c0qyO6+jJYi8p2d65qncMcZhBBVcuqP?= =?us-ascii?q?49uEgeOvODElDxN/XwbiY3T4xoXV5h+GynYwAOQJ6tL1LdrWev4jEMBx7xKRR6?= =?us-ascii?q?JvjvGo7Vks+7y/2+94fcbglUmTaxe69+IAmrpgjNq8cahpdvJLwswRXTuHtIfO?= =?us-ascii?q?pWxWJsJV2Nmhv3+9m98p1+/SlOovwt78FPX7n0cKQ+VrxYES8pM3sp683xtBnM?= =?us-ascii?q?VhWA630BWWgLiBVIAgzF7BbnXpfttybxq+Rw1DWGMcDwULs5Qiqp4bt1RxD0iS?= =?us-ascii?q?cHLz85/3/Risxsl6JQvRatqwViz4LIfI2ZMfxzdb7fc9wHX2pMRthfWSxcDI2/?= =?us-ascii?q?YYUAAeUOMvpDoobnu1cDtwGzCRWiCe7tzDJDm3/43bc90+QkCQzI2BIvEMgIsH?= =?us-ascii?q?jNq9v6Lr0SXvyox6TUyTXDa/JW2TDh6IPVdR0ho++DUqh2ccbIzEkgDRnFgUmK?= =?us-ascii?q?pYP/OzOV0uUNs2+H7+d7VOKvkW8nqx1rrjih3Mchk4/EjZ8bxFDD8CV22oc1Jd?= =?us-ascii?q?ugRUFhZd6kFJpQtyaGN4dsTMMiWWdlszs5xL0eoZO2fSoHxI45yxLCd/CLaZWE?= =?us-ascii?q?7g7nWeqLPzt0mnJodKqiixu28UWs0PPwWteo3FpQridIkcPAum4D2hHR7MWMV+?= =?us-ascii?q?Fz8V272TmV0gDe8uFELl4wlarcM5Mh2aQ/loQJvkjZGi/2hUP2g7WMdkUh4Oeo?= =?us-ascii?q?7eXnba/8qpCAMI90jxnyMqUomsOhHeQ1KgkDUmqB9eiiybHv4Vf1TKhWgvAyiK?= =?us-ascii?q?XVro7WKMQDqq68GQBV04Ij6xilDzeh1dQVhXsHI0xfdxKBloTpPkvBIOrkAvul?= =?us-ascii?q?mVuslDNrx/HBPr39GZjNL2LDkLb9fbpn5U5c0hI/zcpD6JJMFrEBPPXzV1ftu9?= =?us-ascii?q?PCCx85NxW4w+LmCNVmyoMTQnmPA6+cMKPKq1CE/OMvI++WZI8UojnxMfYl5+S9?= =?us-ascii?q?xUM+zHoUfK2o25RfTHGjArxBCEycZTK4id4EFSIOvxEiZO3sklyLFzBJMSWcRa?= =?us-ascii?q?U5sxM2AYTjKI7ZTciEhLiA2zvzSp9bb2YDD1mWGjHhc4GFXOskaTiTPolviGpX?= =?us-ascii?q?BvCaV4Y92ET250fBwL19I7+Ro3VA7MOx5J1O/+TW0CoK23lxBsWZ3XuKSjAmn3?= =?us-ascii?q?kJW3k4xvIn+BAv+hK4yaF9xsdgO5lL/foYAAYgNIKawfYoU4mvCDKERc+ATROd?= =?us-ascii?q?evvjATw1SYhokcQHfU87H8ikhwrG1iyrCvkekLnZXJE=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0DDBgAd42lafOFt0kMMURwBAQEEAQEKA?= =?us-ascii?q?QGEKANxJ4NdmQuCE5FehWmCAgofhzQZBgU0FAEBAQEBAQEBAQEBEgEBCwcPBle?= =?us-ascii?q?COCQBgnAEa0EDAkgXDQYCAQGKMQQBC5ZQnXGBbTomimGEUYIVgz8pglUBg1MLB?= =?us-ascii?q?IE3g0+CZQWkCoEUlE6UJY9HiBOBPDaBcjMaJ06CKgmBewwBgkd3AY5RAQEB?= X-IPAS-Result: =?us-ascii?q?A0DDBgAd42lafOFt0kMMURwBAQEEAQEKAQGEKANxJ4NdmQu?= =?us-ascii?q?CE5FehWmCAgofhzQZBgU0FAEBAQEBAQEBAQEBEgEBCwcPBleCOCQBgnAEa0EDA?= =?us-ascii?q?kgXDQYCAQGKMQQBC5ZQnXGBbTomimGEUYIVgz8pglUBg1MLBIE3g0+CZQWkCoE?= =?us-ascii?q?UlE6UJY9HiBOBPDaBcjMaJ06CKgmBewwBgkd3AY5RAQEB?= X-IronPort-AV: E=Sophos;i="5.46,412,1511823600"; d="scan'208,217";a="252468539" Received: from sava.lunarmania.com ([67.210.109.225]) by mail3-smtp-sop.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 25 Jan 2018 15:04:50 +0100 Received: from wifi-eduroam-trans.univ-tlse3.fr ([195.220.58.237]:12347 helo=[172.17.51.127]) by sava.lunarmania.com with esmtpsa (TLSv1:DHE-RSA-AES128-SHA:128) (Exim 4.87) (envelope-from ) id 1eei90-0005sD-1a for caml-list@inria.fr; Thu, 25 Jan 2018 06:04:46 -0800 To: Mailing List OCaml From: Jean-Marc Alliot Message-ID: Date: Thu, 25 Jan 2018 15:04:43 +0100 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.1.1 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="------------2FF1943C5F00B15F61E3612D" X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - sava.lunarmania.com X-AntiAbuse: Original Domain - inria.fr X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - irit.fr X-Get-Message-Sender-Via: sava.lunarmania.com: authenticated_id: jmall1/only user confirmed/virtual account not confirmed X-Authenticated-Sender: sava.lunarmania.com: jmall1 Subject: [Caml-list] In need of an ocaml guru This is a multi-part message in MIME format. --------------2FF1943C5F00B15F61E3612D Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Dear Ocaml Gurus, I have recently hit a problem that I can't really solve by myself, probably because I lack a good understanding of the way ocaml works really (I am more a very long-time faithful user coming from procedural languages than a specialist of functional languages). The problem that I am going to describe might look slightly far-fetched in ocaml, however it occured in a completely natural way in a Haskell program I was writing, and it took me quite a long time to spot it; then I translated it in ocaml, because I am more at ease with it. The program is included at the bottom of this message. It is short and can be compiled without any additional modules. The idea is to mimick (more or less...) the behavior of monads and more specifically of the Haskell IO monad. However, no previous knowledge of Haskell or of monads is required. The program implements 4 kinds of monads that all respect the monad signature. The most interesting implementations are Monad3 and Monad4. With Monad3, test has type (unit Monad3.t) which is a (unit -> unit) in "disguise". However running the resulting program prints "false", meaning that (fun v -> return (Printf.printf "%b\n" v)) has been executed (and the search2 function has also been executed of course). Opening Monad4 instead of Monad3 gives a completely different result while it looks to a beotian like me that Monad3 is just Monad4 with a type constructor added... Now "false" is not printed. And if I try now to compute (test ()) to get the actual answer, the program runs forever (well forever might not be the exact word but I was not patient enough to wait). Let's make a very simple modification. In the third line of search2, it is easy to see that the value of acc doesn't matter as the lambda expression it is applied to is (fun _ -> ...). So it can be replaced (you can comment out acc and uncomment the next line) by anything such as (return false), and this should not change the result of the program. Well, it changes at least the behaviour... Now (test ()) is computed instantaneously and prints (correctly) false... I would really appreciate if someone could give me answers to the following questions: 1) Why the programs with Monad3 and Monad4 behave differently? 2) Why does the program with Monad4 run apparently forever (or a very long time)? 3) Why changing acc by (return false) in the program with Monad4 computes immediately the result? Of course, in more than 25 years of programming with caml, I have never faced such issues. This is why I am going to stick with ocaml and forget trying to use Haskell. However, I've spent quite a lot of time on this already, and understanding this would make that time well spent, instead of lost... :-) Friendly (* module Monad : sig type 'a t val return : 'a -> 'a t val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t end *) module Monad = struct type 'a t = M of 'a;; let return x = M x;; let (>>=) (M m) (f : ('a -> 'b t)) = (f m);; end;; module Monad1 = struct type 'a t = M1 of 'a Lazy.t;; let return x = M1 (lazy x);; let (>>=) (M1 m) (f : ('a -> 'b t)) = f (Lazy.force m) ;; end;; module Monad2 = struct type 'a t = M2 of (unit -> 'a);; let return x = M2 (fun () -> x);; let (>>=) (M2 m) (f : ('a -> 'b t)) = (f (m ())) ;; end;; module Monad3 = struct type 'a t = M3 of (unit -> 'a);; let return x = M3 (fun () -> x);; let (>>=) (M3 m) (f : ('a -> 'b t)) = let (M3 tmp) = f (m()) in M3 (fun () -> tmp ());; end;; module Monad4 = struct type 'a t = (unit -> 'a);; let return x = (fun () -> x);; let (>>=) m (f : ('a -> 'b t)) = fun () -> (f (m ())) ();; end;; (* Use any Monad here *) open Monad4;; (* Poor man's multiset *) let rec delete x (hd::tl) = if x=hd then tl else hd::(delete x tl);; let insert x s = x::s;; let fold f b s = List.fold_right f s b;; let fromlist s = s ;; let search2 mynumbers nb = let rec ins numbers acc = (>>=) acc (* (return false) *) (fun _ -> fold (fun x acc1 -> let numbers2 = delete x numbers in fold (fun y acc2 -> let numbers3 = delete y numbers2 and res = x + y in if res = nb then (return true) else ins (insert res numbers3) acc2) acc1 numbers2) acc numbers) in ins mynumbers (return false);; let b = fromlist [1;2;3;4];; (* Monad : val test : unit Monad.t Exec: False Monad1: val test : unit Monad1.t Exec: False Monad2: val test : unit Monad2.t Exec: False Monad3: val test : unit Monad3.t Exec: False Monad4: val test : unit -> unit Exec: ---- *) let test = (>>=) (search2 b 99999999) (fun v -> return (Printf.printf "%b\n" v));; (* Only use for Monad4. It runs forever... *) (* let main4 = test ();; *) - Jean-Marc Alliot - Centre International de Mathématiques et d'Informatique de Toulouse (Labex CIMI) Directeur Adjoint - mailto:jean-marc.alliot@irit.fr - Web: http://www.alliot.fr/fpro.html.fr --------------2FF1943C5F00B15F61E3612D Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: 8bit Dear Ocaml Gurus,

I have recently hit a problem that I can't really solve by myself, probably because I lack a good understanding of the way ocaml works really (I am more a very long-time faithful user coming from procedural languages than a specialist of functional languages).
 
The problem that I am going to describe might look slightly far-fetched in ocaml, however it occured in a completely natural way in a Haskell program I was writing, and it took me quite a long time to spot it; then I translated it in ocaml, because I am more at ease with it.

The program is included at the bottom of this message. It is short and can be compiled without any additional modules.
The idea is to mimick (more or less...) the behavior of monads and more specifically of the Haskell IO monad. However, no previous knowledge of Haskell or of monads is required.

The program implements 4 kinds of monads that all respect the monad signature. The most interesting implementations are Monad3 and Monad4.

With Monad3, test has type (unit Monad3.t) which is a (unit -> unit) in "disguise". However running the resulting program prints "false", meaning that (fun v -> return (Printf.printf "%b\n" v)) has been executed (and the search2 function has also been executed of course).

Opening Monad4 instead of Monad3 gives a completely different result while it looks to a beotian like me that Monad3 is just Monad4 with a type constructor added...
Now "false" is not printed. And if I try now to compute (test ()) to get the actual answer, the program runs forever (well forever might not be the exact word but I was not patient enough to wait).

Let's make a very simple modification. In the third line of search2, it is easy to see that the value of acc doesn't matter as the lambda expression it is applied to is (fun _ -> ...). So it can be replaced (you can comment out acc and uncomment the next line) by anything such as (return false), and this should not change the result of the program. Well, it changes at least the behaviour... Now (test ()) is computed instantaneously and prints (correctly) false...

I would really appreciate if someone could give me answers to the following questions:
1) Why the programs with Monad3 and Monad4 behave differently?
2) Why does the program with Monad4 run apparently forever (or a very long time)?
3) Why changing acc by (return false) in the program with Monad4 computes immediately the result?

Of course, in more than 25 years of programming with caml, I have never faced such issues. This is why I am going to stick with ocaml and forget trying to use Haskell. However, I've spent quite a lot of time on this already, and understanding this would make that time well spent, instead of lost... :-)

Friendly



(*
module Monad :
  sig
    type 'a t
    val return : 'a -> 'a t
    val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t
  end
 *)


module Monad = struct
  type 'a t = M of 'a;;
  let return x = M x;;
  let (>>=) (M m) (f : ('a -> 'b t)) = (f m);;
end;;

module Monad1 = struct
  type 'a t = M1 of 'a Lazy.t;;
  let return x = M1 (lazy x);;
  let (>>=) (M1 m) (f : ('a -> 'b t)) =  f (Lazy.force m) ;;
end;;

module Monad2 = struct
  type 'a t = M2 of (unit -> 'a);;
  let return x = M2 (fun () -> x);;
  let (>>=) (M2 m) (f : ('a -> 'b t)) =  (f (m ())) ;;
end;;

module Monad3 = struct
  type 'a t = M3 of (unit -> 'a);;
  let return x = M3 (fun () -> x);;
  let (>>=) (M3 m) (f : ('a -> 'b t)) =
    let (M3 tmp) = f (m()) in
    M3 (fun () -> tmp ());;
end;;

module Monad4 = struct
  type 'a t = (unit -> 'a);;
  let return x = (fun () -> x);;
  let (>>=) m (f : ('a -> 'b t)) = fun () -> (f (m ())) ();;
end;;

(* Use any Monad here *)
open Monad4;;

(* Poor man's multiset *)
let rec delete x (hd::tl) = if x=hd then tl else hd::(delete x tl);;
let insert x s = x::s;;
let fold f b s = List.fold_right f s b;;
let fromlist  s = s ;;

let search2 mynumbers nb =
  let rec ins numbers acc =
    (>>=)
      acc
      (* (return false) *)
      (fun _ ->  
        fold
          (fun x acc1 ->
            let numbers2 = delete x numbers
            in fold
                 (fun y acc2 ->
                   let numbers3 = delete y numbers2
                   and res = x + y
                   in if res = nb
                      then (return true)
                      else ins (insert res numbers3) acc2)
                 acc1
                 numbers2)
          acc
          numbers) in
  ins mynumbers (return false);;

let b = fromlist [1;2;3;4];;

(*
Monad : val test : unit Monad.t     Exec: False
Monad1: val test : unit Monad1.t    Exec: False
Monad2: val test : unit Monad2.t    Exec: False
Monad3: val test : unit Monad3.t    Exec: False
Monad4: val test : unit -> unit     Exec: ----
 *)
let test =
  (>>=)
    (search2 b 99999999)
    (fun v -> return (Printf.printf "%b\n" v));;

(* Only use for Monad4.
   It runs forever... *)
(*
let main4 = test ();;
*)

- Jean-Marc Alliot
- Centre International de Mathématiques et d'Informatique de Toulouse (Labex CIMI)
  Directeur Adjoint
- mailto:jean-marc.alliot@irit.fr
- Web: 
http://www.alliot.fr/fpro.html.fr

--------------2FF1943C5F00B15F61E3612D--