matijapretnar/eff

return a list from external.ml

Closed this issue · 12 comments

type value =
  | Const of Const.t
  | Tuple of value list
  | Record of (OldUtils.field, value) Assoc.t
  | Variant of OldUtils.label * value option
  | Closure of closure
  | Handler of (result -> result)

I was trying to use Split as an external function
I got it to work but the return value is of this type (Tuple of value list)
However, I want to return a string list instead of tuple

I tried to make a new constructor for lists but still the value retuned comes as a tuple

type value =
  | Const of Const.t
  | Tuple of value list
  | List of value list
  | Record of (OldUtils.field, value) Assoc.t
  | Variant of OldUtils.label * value option
  | Closure of closure
  | Handler of (result -> result)

Any ideas?

Thanks,
Ghadeer

Lists are encoded as Variants with the labels OldUtils.cons and OldUtils.label, so you probably need to use that to implement split.

Is there any special reason you are trying to use split as an external function?
It seems to be easy enough to implement in pervasives.eff.

I wanted to implement it in pervasives.eff as this

let rec split l d =
    match  l with
         []  ->  [l]
    | (c::cs) -> let rest = split cs d in
                match c = d with
                true ->  (""::rest)
                | false -> ( c  ^ head rest ) :: tail rest
;;

but I got this issue

This expression has type string list but it should have type string.

When I looked online, they said I need to covert the string to list of chars using this method

let string_of_char c = String.make 1 c

(* Converts a string to a list of chars *)
let explode str =
  let rec explode_inner cur_index chars = 
    if cur_index < String.length str then
      let new_char = str.[cur_index] in
      explode_inner (cur_index + 1) (chars @ [new_char])
    else chars in
  explode_inner 0 []

(* Converts a list of chars to a string *)
let rec implode chars =
  match chars with
    [] -> ""
    | h::t ->  string_of_char h ^ (implode t)

so I thought using it as external is more convient

Ah, I see, I though you were trying to implement List.split.
The way I would try to do this, is add external functions equivalent to String.length and String.get.
That probably requires modifying Const.ml and Const.mli to safely extract the string from the constant.
Afterwards it is probably possible to implement split in pervasives.eff using the above two functions.

You can however try to modify your existing implementation to return a Variant with the proper list constructor.

This is what I was about to do
I already have "get" and would add "length"
and then implement it in pervasives.eff

Thank you for your help and advice!

What is your split supposed to do, in words? It looks like you just have a simple bug in the Eff code, you should try to fix that first.

split takes a string and a char and split the string to a list of strings using the char

$ split "Hello Hi" ' '
["Hello"; "Hi"]

The code you wrote does not do that (and I don't see what it's supposed to do). But yeah, if that's what you want ot do, you'll have to add characters to Eff. And may I ask what this is used for later on?

What is spit "foo bar bar qux " ' ' supposed to do? Split on all the spaces? Just the first one?

spit "foo bar bar qux " ' '
["foo"; "bar" ; "bar"; "qux"]

I need split for parsing the input I read from the file
I already took care of chars

Here's split that works with lists:

let split lst x =
  let rec loop acc = function
    | [] -> [acc]
    | y :: ys ->
       if x = y then
         acc :: loop [] ys
       else
         loop (acc @ [y]) ys
  in
  loop [] lst
;;

Example:

# split [1;2;4;0;5;6;0;8;7] 0 ;;
- : int list list = [[1; 2; 4]; [5; 6]; [8; 7]]
# split ["H";"e";"l";"l";"o";" ";"w";"o";"r";"l";"d"] " " ;;
- : string list list = [["H"; "e"; "l"; "l"; "o"]; ["w"; "o"; "r"; "l"; "d"]]

This should be easy to adapt to strings and characters.

Yes that works, but I have to use explode

let split lst x =
  let rec loop acc = function
    | [] -> [acc]
    | y :: ys ->
       if x = y then
         acc :: loop [] ys
       else
         loop (acc @ [y]) ys
  in
  loop [] (explode lst)

Thank you so much!

Whatever you're doing, it seems this will be inefficient. Perhaps it doesn't matter.