The problem is almost certainly that "open_file" should be using "open_in_bin" instead of "open_in", since you are doing binary input.
In particular, ultimately the lexer created using "from_channel" simply uses "Pervasives.input". In the case of files opened using "open_in" this reads directly from the underlying stream, as indicated by the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/// Attempt to input the given number of bytes from the channel, writing them into the /// buffer at the given start position. Does not block if the bytes are not available. /// /// The use of this function with a channel performing byte-to-character translation (e.g. one /// created with open_in, open_in_utf8 or open_in_encoded, or one /// or built from a StreamReader or TextReader) is not recommended. /// Instead, open the channel using open_in_bin or binary_reader_to_in_channel. /// /// If used with a StreamReader channel, i.e. one created using /// open_in, open_in_utf8 or open_in_encoded, or one /// or built from a StreamReader, this function reads bytes directly from the underlying /// BaseStream. This may not be appropriate if any other input techniques are being /// used on the channel. ///
Please feel free to post your entire sample.
Don
Hi Don,
Thanks - that does solve the problem, though I dont understand why. The source file I am parsing is not binary. I guess your comment "you are doing binary input" means fslex is doing binary input?
I should point out that I actually have two versions of the "read_x_file_header" function - one for ocaml and one for f#. Do you have any comments on how I could unify these? Apart from a minor incompatibility in fslex (*) this is the only difference I had to contend with.
ocaml:
1 2 3 4 5 6 7
let read_x_file_header file = let s = String.create 16 in for j=0 to 15 do s.[j] <- input_char file; done; if (not (s = "xof 0303txt 0032")) && (not (s = "xof 0303txt 0064")) then failwith "Dont recognise header."
f#:
1 2 3 4 5 6
let read_x_file_header file = let rec make n = if n = 0 then "" else (String.of_char (input_char file)) ^ (make (n-1)) in let s = make 16 in if (not (s = "xof 0303txt 0032")) && (not (s = "xof 0303txt 0064")) then failwith "Dont recognise header."
Cheers,
Andy
(*)
1
| ['A'-'Z' 'a'-'z'] ['A'-'Z' 'a'-'z' '0'-'9' '_'] * as id { ... }
needs to be redone as
1
| ['A'-'Z' 'a'-'z'] ['A'-'Z' 'a'-'z' '0'-'9' '_'] * { let id = lexeme lexbuf in ... }
Hi Andy,
Yes, fslex does binary input, in the sense that it reads bytes directly, rather than applying a Unicode interpretation (i.e. encoding/decoding) to the bytes.
On .NET and with F# the text/binary input distinction is really related to whether you are applying a Unicode interpretation to the bytes or not. Text mode functions such as "input_line" and "input_char" only really make sense in conjunction with a Unicode interpretation (or you have a default interpreation chosen for you) - for example, what Unicode character would bytes in the range 0x80 - 0xFF represent? This is not specified by OCaml, since there characters are just bytes, rather than being Unicode characters. This means you can't really mix and match with doing character input with "input_char" and byte input using "input".
The upshot is that when writing I/O code that cross compiles with OCaml you should use binary mode input more often, since from the .NET persepctive OCaml is really doing binary mode input most of the time, as it is reading input without applying a Unicode encoding.
To write binary-mode functions like read_x_file_header that work correctly with both OCaml and F# you should develop an OCaml module that makes OCaml compatible with F#. In particular you should add a Bytearray module that is compatible with the F# Bytearray module (see Microsoft.FSharp.MLLib.Bytearray). This F# module exists precisely to allow the development of cross-compiling byte-oriented I/O functionality. Here are some sample functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
(*IF-OCAML*) (* This module is an OCaml implementation of an F#-compatible Bytearray module. * When using OCaml bytearrays are strings, and when using F# they are of type "byte[]" * You can easily implement other functions in the F# bytearray module in this way. *) module Bytearray = struct type bytearray = string let create n x = String.make n x let zero_create n x = String.make n '0' let ascii_to_string (b:bytearray) : string = b end (*ENDIF-OCAML*) let read_x_file_header file = let buf = Bytearray.zero_create 16 in let n = input file buf 0 16 in if n <> 16 or (let text = Bytearray.ascii_to_string buf in text <> "xof 0303txt 0032" && text <> "xof 0303txt 0064") then failwith "Dont recognise header."
Hi Don,
I think I am beginning to understand now. My usual interpretation of what text/binary mode means is totally wrong in this case. So text mode means unicode. Cool.
I have implemented the code you suggested and now it cross compiles between ocaml and f# without a hitch which is nice.
I have also been playing around trying to access the f# code from c# (blimey you dont half write complex type systems in ML with barely a thought). One issue I have is that I cant seem to access a function from one of my modules (other functions in that module work) - it complains that "no overload for method 'write_xfile_data' takes '1' argument". I beg to differ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
let write_xfile_data d = let rec write_simple_type i data = match data with | X_int s -> os (i ^ " i " ^ s ^ "\n") | X_real s -> os (i ^ " r " ^ s ^ "\n") | X_string s -> os (i ^ " s " ^ s ^ "\n") | X_compound d -> os (i ^ " <c\n"); iter (write_simple_type i) d; os (i ^ " c>\n") | X_array (T_string_index(s), d) | X_array (T_int_index(s), d) -> os (i ^ " <a " ^ s ^ "\n"); iter (write_simple_type i) d; os (i ^ " a>\n") in let rec write_xfile_data1 i d = let tname, oname, data, hier = d in os (i ^ tname ^ " " ^ oname ^ " {\n"); iter (fun data -> match data with | X_data d -> write_simple_type i d | _ -> () ) data; iter (fun hier -> match hier with | X_object o -> write_xfile_data1 (i ^ " ") o | _ -> () ) hier; os (i ^ "}\n") in write_xfile_data1 "" d
And the c# code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
using Microsoft.FSharp; using System; using X_templates = Microsoft.FSharp.List<Xtypes.xfile_el_t>; using X_data = Microsoft.FSharp.List<Microsoft.FSharp.Tuple<string,string, Microsoft.FSharp.List<Xtypes.x_object_el_t>, Microsoft.FSharp.List<Xtypes.x_object_el_t>>>; using X_object = Microsoft.FSharp.Tuple<Microsoft.FSharp.List<Xtypes.xfile_el_t>, Microsoft.FSharp.List<Microsoft.FSharp.Tuple<string,string, Microsoft.FSharp.List<Xtypes.x_object_el_t>, Microsoft.FSharp.List<Xtypes.x_object_el_t>>>>; class Xtest { static X_templates GetTemplates(X_object x) { return x.Item1; } static X_data GetData(X_object x) { return x.Item2; } static void Main() { X_templates xtemplates = GetTemplates(Xread.load_x_file(X_templates.Nil, "templates.x")); X_data xobj = GetData(Xread.load_x_file(xtemplates, "airplane.x")); Xwrite.write_xfile_template(xtemplates.Head); Xwrite.write_xfile_data(xobj.Head); } }
It's more than possible that I've done something stupid given my level of expertise with these tools.
Thanks for code formatting suggestion. I have altered my account settings so that I can see them in the tool bar.
Cheers,
Andy
The representation of public F# functions in the .NET IL is type-directed. In particular, functions taking tupled arguments are compiled as if they take multiple arguments, regardless of whether the functions are written
1
let f p = ...
or
1
let f (x,y) = ...
So write_x_file_data has a tuple type (indeed a triple), hence will be compiled as a .NET method that takes 3 arguments. That's just the way things work.
Given you're writing code you want to consume from C# and you're using tuples for types that are important across the interop boundary you may wish to use named data types in your F# code to replace tuples. This is really easy, for example,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
type x_data = Data of string * string * x_object_el_t list * x_data list let write_xfile_data d = ... let rec write_xfile_data1 i (Data(tname, oname, data, hier)) = ... write_xfile_data1 "" d
Don
Thanks - thats explains that then. So if I had a function which was
1
let blah (x,y) z = ...
then that would expand to a c# function of 3 arguments.
I'm really starting to get a feel for just how powerful this whole .net malarky is. I've just had a play with the DbgCLR tool and I am seriously impressed. Ocaml's days may be numbered (and I really like ocaml).
Cheers,
Andy
BTW the nice formatting for the pasted code above comes from pasting in "raw text" into the "Design" tab and then marking it with the "F#" code highlighter marker next to the "Insert Simley" box (again in the "Design" tab).
Pasting in code directly from visual studio does not look great. Instead paste into notepad, and copy from notepad into the text editor in the "Design" tab.
Topic tags
- f# × 3705
- websharper × 1897
- compiler × 286
- functional × 201
- ui next × 139
- c# × 121
- classes × 97
- web × 97
- .net × 84
- book × 84
- async × 76
- ui.next × 67
- bug × 54
- core × 49
- website × 49
- server × 45
- parallel × 43
- ui × 43
- enhancement × 41
- parsing × 41
- testing × 41
- trywebsharper × 41
- typescript × 37
- html × 35
- javascript × 35
- owin × 35
- asynchronous × 30
- monad × 28
- ocaml × 28
- tutorial × 27
- warp × 27
- haskell × 26
- sitelet × 25
- linq × 22
- workflows × 22
- wpf × 20
- fpish × 19
- introduction × 19
- silverlight × 19
- sitelets × 19
- monodevelop × 17
- rpc × 17
- suave × 17
- piglets × 16
- collections × 15
- feature request × 15
- jquery × 15
- templates × 15
- getting started × 14
- pipeline × 14
- kendoui × 13
- reactive × 12
- 4.1.0.171 × 11
- monads × 11
- opinion × 10
- 4.0.190.100-rc × 9
- deployment × 9
- fixed × 9
- formlets × 9
- in × 9
- json × 9
- plugin × 9
- proposal × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- highcharts × 8
- how-to × 8
- python × 8
- 4.1.1.175 × 7
- complexity × 7
- documentation × 7
- visual studio × 7
- 4.1.2.178 × 6
- lisp × 6
- real-world × 6
- released in 4.0.192.103-rc × 6
- remoting × 6
- resources × 6
- scala × 6
- websharper ui.next × 6
- workshop × 6
- xaml × 6
- 4.0.193.110 × 5
- 4.2.3.236 × 5
- aspnetmvc × 5
- authentication × 5
- azure × 5
- bootstrap × 5
- conference × 5
- dsl × 5
- formlet × 5
- java × 5
- list × 5
- metaprogramming × 5
- ml × 5
- released in Zafir.4.0.188.91-beta10 × 5
- sql × 5
- visualstudio × 5
- websharper.forms × 5
- zafir × 5
- 4.0.192.106 × 4
- 4.0.195.127 × 4
- 4.1.0.38 × 4
- 4.2.1.86 × 4
- 4.2.6.118 × 4
- css × 4
- example × 4
- extensions × 4
- fsi × 4
- fsx × 4
- html5 × 4
- jqueryui × 4
- lift × 4
- reflection × 4
- remote × 4
- rest × 4
- spa × 4
- teaching × 4
- template × 4
- websocket × 4
- wontfix × 4
- 4.0.196.147 × 3
- 4.1.0.34 × 3
- 4.1.6.207 × 3
- 4.2.1.223-beta × 3
- 4.2.11.258 × 3
- 4.2.4.114 × 3
- 4.2.4.247 × 3
- 4.2.5.115 × 3
- 4.2.6.253 × 3
- 4.2.9.256 × 3
- ajax × 3
- alt.net × 3
- aml × 3
- asp.net mvc × 3
- canvas × 3
- cloudsharper × 3
- compilation × 3
- database × 3
- erlang × 3
- events × 3
- extension × 3
- file upload × 3
- forums × 3
- inline × 3
- issue × 3
- kendo × 3
- macro × 3
- mono × 3
- msbuild × 3
- mvc × 3
- pattern × 3
- piglet × 3
- released in Zafir.4.0.187.90-beta10 × 3
- svg × 3
- type provider × 3
- view × 3
- 4.1.1.64 × 2
- 4.1.5.203 × 2
- 4.1.7.232 × 2
- 4.2.10.257 × 2
- 4.2.3.111 × 2
- 4.2.5.249 × 2
- android × 2
- asp.net × 2
- beginner × 2
- blog × 2
- chart × 2
- client × 2
- client server app × 2
- clojure × 2
- computation expressions × 2
- constructor × 2
- corporate × 2
- courses × 2
- cufp × 2
- d3 × 2
- debugging × 2
- direct × 2
- discriminated union × 2
- docs × 2
- elm × 2
- endpoint × 2
- endpoints × 2
- enterprise × 2
- entity framework × 2
- event × 2
- f# interactive × 2
- fable × 2
- flowlet × 2
- formdata × 2
- forms × 2
- fsc × 2
- google maps × 2
- hosting × 2
- http × 2
- https × 2
- iis 8.0 × 2
- install × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- jquery mobile × 2
- keynote × 2
- lens × 2
- lenses × 2
- linux × 2
- listmodel × 2
- mac × 2
- numeric × 2
- oauth × 2
- obfuscation × 2
- offline × 2
- oop × 2
- osx × 2
- packaging × 2
- pattern matching × 2
- performance × 2
- pipelines × 2
- q&a × 2
- quotation × 2
- reference × 2
- released in Zafir.4.0.185.88-beta10 × 2
- rx × 2
- script × 2
- security × 2
- self host × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- tutorials × 2
- type × 2
- url × 2
- var × 2
- websharper.charting × 2
- websharper4 × 2
- websockets × 2
- wig × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- 4.0.194.126 × 1
- 4.1.3.184 × 1
- 4.1.4.189 × 1
- 4.2.0.214-beta × 1
- 4.2.12.259 × 1
- 4.2.2.231-beta × 1
- 4.2.8.255 × 1
- Canvas Sample Example × 1
- DynamicStyle Animated Style × 1
- Fixed in 4.0.190.100-rc × 1
- Released in Zafir.UI.Next.4.0.169.79-beta10 × 1
- SvgDynamicAttribute × 1
- WebComponent × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- actor × 1
- addin × 1
- agents × 1
- aggregation × 1
- agile × 1
- alter session × 1
- animation × 1
- anonymous object × 1
- apache × 1
- api × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net core × 1
- asp.net integration × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- attributes × 1
- authorization × 1
- b-tree × 1
- back button × 1
- badimageformatexception × 1
- bash script × 1
- batching × 1
- binding-vars × 1
- bistro × 1
- body × 1
- bundle × 1
- camtasia studio × 1
- cas protocol × 1
- charts × 1
- clarity × 1
- class × 1
- cli × 1
- clipboard × 1
- clojurescript × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- color zones × 1
- combinator × 1
- combinators × 1
- compile × 1
- compile code on server × 1
- config × 1
- confirm × 1
- content × 1
- context × 1
- context.usersession × 1
- continuation-passing style × 1
- coords × 1
- cordova × 1
- cors × 1
- coursera × 1
- cross-domain × 1
- csla × 1
- current_schema × 1
- custom content × 1
- data × 1
- data grid × 1
- datetime × 1
- debug × 1
- declarative × 1
- delete × 1
- devexpress × 1
- dhtmlx × 1
- dictionary × 1
- directattribute × 1
- disqus × 1
- distance × 1
- do binding × 1
- doc elt ui.next upgrade × 1
- docker × 1
- dojo × 1
- dol × 1
- dom × 1
- domain × 1
- du × 1
- duf-101 × 1
- dynamic × 1
- eastern language × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- enums × 1
- error × 1
- etw × 1
- euclidean × 1
- eventhandlerlist × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- failed to translate × 1
- fake × 1
- fantomas × 1
- fear × 1
- float × 1
- form × 1
- form-data × 1
- forum × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- fsunit × 1
- function × 1
- functional style × 1
- game × 1
- games × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- getting-started × 1
- google × 1
- google.maps × 1
- grid × 1
- group × 1
- guide × 1
- hash × 1
- headers × 1
- hello world example × 1
- heroku × 1
- highchart × 1
- history × 1
- how to × 1
- html-templating × 1
- http405 × 1
- httpcontext × 1
- hubfs × 1
- i18n × 1
- ie 8 × 1
- if-doc × 1
- iis × 1
- image × 1
- images × 1
- inheritance × 1
- initialize × 1
- input × 1
- install "visual studio" × 1
- installer × 1
- int64 × 1
- interfaces × 1
- internet explorer × 1
- interop × 1
- interpreter × 1
- io × 1
- iobservable × 1
- ios × 1
- iot × 1
- ipad × 1
- isomorphic × 1
- javascript optimization × 1
- javascript semanticui resources × 1
- jquery-plugin × 1
- jquery-ui × 1
- jquery-ui-datepicker × 1
- js × 1
- kendo datasource × 1
- kendochart × 1
- kendoui compiler × 1
- knockout × 1
- l10n × 1
- learning × 1
- library × 1
- libs × 1
- license × 1
- licensing × 1
- lineserieszonescfg × 1
- local setting × 1
- localization × 1
- logging × 1
- loop × 1
- macros × 1
- mailboxprocessor × 1
- mapping × 1
- maps × 1
- markerclusterer × 1
- markup × 1
- marshal × 1
- math × 1
- mathjax × 1
- message × 1
- message passing × 1
- message-passing × 1
- meta × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- mix × 1
- mobile installation × 1
- mod_mono × 1
- modal × 1
- module × 1
- mouseevent × 1
- mouseposition × 1
- multidimensional × 1
- multiline × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- native × 1
- nested × 1
- nested loops × 1
- node × 1
- nunit × 1
- object relation mapper × 1
- object-oriented × 1
- om × 1
- onboarding × 1
- onclick × 1
- optimization × 1
- option × 1
- orm × 1
- os x × 1
- output-path × 1
- override × 1
- paper × 1
- parameter × 1
- persistence × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- post × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- privacy × 1
- private × 1
- profile × 1
- programming × 1
- project × 1
- project euler × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- proxy × 1
- ptvs × 1
- public × 1
- pure f# × 1
- purescript × 1
- qna × 1
- quant × 1
- query sitelet × 1
- question × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- reactjs × 1
- real-time × 1
- ref × 1
- region × 1
- released in 4.0.190.100-rc × 1
- reporting × 1
- responsive design × 1
- rest api × 1
- rest sitelet × 1
- restful × 1
- round table × 1
- router × 1
- routing × 1
- rpc reverseproxy × 1
- runtime × 1
- sales × 1
- sample × 1
- sampleapp × 1
- scriptcs × 1
- scripting × 1
- search × 1
- self hosted × 1
- semanticui × 1
- sequence × 1
- serialisation × 1
- service × 1
- session-state × 1
- sharepoint × 1
- signals × 1
- sitelet website × 1
- sitelet.protect × 1
- sitlets × 1
- slickgrid × 1
- source code × 1
- sqlentityconnection × 1
- ssl × 1
- standards × 1
- static content × 1
- stickynotes × 1
- streamreader × 1
- stress × 1
- strong name × 1
- structures × 1
- submitbutton × 1
- subscribe × 1
- svg example html5 websharper.ui.next × 1
- sweetalert × 1
- system.datetime × 1
- system.reflection.targetinvocationexception × 1
- table storage × 1
- targets × 1
- tdd × 1
- templates ui.next × 1
- templating × 1
- text parsing × 1
- three.js × 1
- time travel × 1
- tls × 1
- tooltip × 1
- tracing × 1
- tsunamiide × 1
- turkish × 1
- twitter-bootstrap × 1
- type erasure × 1
- type inference × 1
- type providers × 1
- type-providers × 1
- typeprovider × 1
- ui next forms × 1
- ui-next × 1
- ui.next jqueryui × 1
- ui.next charting × 1
- ui.next formlets × 1
- ui.next forms × 1
- ui.next suave visualstudio × 1
- ui.next templating × 1
- unicode × 1
- unittest client × 1
- upload × 1
- usersession × 1
- validation × 1
- vb × 1
- vb.net × 1
- vector × 1
- view.map × 1
- visal studio × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- vs2017 compiler zafir × 1
- vsix × 1
- web api × 1
- web-scraping × 1
- webapi × 1
- webcomponents × 1
- webforms × 1
- webgl × 1
- webrtc × 1
- webshaper × 1
- websharper async × 1
- websharper codemirror × 1
- websharper f# google × 1
- websharper forms × 1
- websharper reactive × 1
- websharper rpc × 1
- websharper sitelets routing × 1
- websharper warp × 1
- websharper-interface-generator × 1
- websharper.chartsjs × 1
- websharper.com × 1
- websharper.exe × 1
- websharper.owin × 1
- websharper.ui.next × 1
- websharper.ui.next jquery × 1
- websockets iis × 1
- why-websharper × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- www.grabbitmedia.com × 1
- xamarin × 1
- xml × 1
- yeoman × 1
- yield × 1
- zafir beta × 1
- zafir websharper4 × 1
- zarovizsga × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy |
Built with WebSharper |
Hi,
I'm trying to write a parser for .x files which is compatible with caml and f#.
At the moment the caml version works but the f# port doesn't quite.
What I have is a small bit of code which reads 16 byte of data from the input stream before parsing begins. This removes the .x file header.
In caml this works fine but in f# the parser always fails on the first line. If I manually remove the header from the x file and dont read it then both versions work.
Is there something in the f# lexer that resets the file pointer when starting to lex?
Cheers,
Andy