I would like to have a few lines of code at the start of my OCaml input file to have toplevel remember the last expression typed all the time, under the name of it. I.e., I want to have:
# 3 + 4;;
val it : int = 7
# it;;
val it : int = 7
# let foo = 42;;
val foo : int = 42
# it + 130;;
val it : int = 137
#
But I don't want to build a custom toplevel or use camlp5 or anything fancy like that.
What I currently do (in OCaml version 4.02.3, I don't know why I have that version; but I hope the exact version doesn't matter?) is the following:
#directory "+compiler-libs";;
#load "/opt/src/ocaml-4.02.3/utils/warnings.cmo";;
#load "/opt/src/ocaml-4.02.3/parsing/location.cmo";;
let convert_phrase x =
match x with
| Parsetree.Ptop_def
[{Parsetree.pstr_desc = Parsetree.Pstr_eval (e, a)}] ->
Parsetree.Ptop_def
([{Parsetree.pstr_desc =
Parsetree.Pstr_value (Asttypes.Nonrecursive,
[{Parsetree.pvb_pat =
{Parsetree.ppat_desc =
Parsetree.Ppat_var (Location.mknoloc "it");
Parsetree.ppat_loc = Location.none;
Parsetree.ppat_attributes = []};
Parsetree.pvb_expr = e;
Parsetree.pvb_attributes = a;
Parsetree.pvb_loc = Location.none}]);
Parsetree.pstr_loc = Location.none}])
| x -> x;;
Toploop.parse_toplevel_phrase :=
let parse_toplevel_phrase = !Toploop.parse_toplevel_phrase in
fun x -> convert_phrase (parse_toplevel_phrase x);;
And that kind of works.
My question: if I just do the #directory "+compiler-libs";; thing, I can access the Toploop and Parsetree modules, but I cannot access the Location module! What is the reason for that? I find having to load .cmo files from my source directories very unattractive.
So is there a way to do what I want without having to have a source tree available?
Or, in other words: why the difference between Toploop and Location, in this respect?
In short, what you should load is not individual .cmo files but
#load "ocamlcommon.cma";;
which is in +compiler-libs directory.
The differences between Parsetree, Toploop and Location are subtle...
In OCaml, data types and their constructors become accessible only with adding its directory to the load path (by #directory "<dir>"). No object code loading (by #load) is required for them.
Parsetree is so called "mli only module": it has only data type definitions and no values are defined. Therefore everything in Parsetree is accessible only by putting it into the load path.
Location defines types and values. Its data types and constructors are accessible without loading the object file but values require the loading. In this case, the object location.cmo is loaded when you load ocamlcommon.cma which archives it.
Toploop is a tricky one. You can access the values of Toploop even without loading toploop.cmo, since Toploop is linked and already available in OCaml toplevel.
Related
I am trying to go through a predefined dir path set but I only have the prefix of the path
I have tried use include? or find a method that does that.
I can only think about the trivial solution of define a regexp and go for each in the set, but that seems to be not so ruby-like style
require 'set'
legal_paths = Set['A/B/C', 'A/D/E', 'A/F/G']
Dir.glob('**/system.log').each do |fd|
if failed_tests_path.include?(fd) #fd for example = A/F/G/E/system.log, A/B/C/K/system.log etc...
puts fd
end
end
I want fd to be only system.log files that the paths are including inside the set (the set holds the prefix to the path)
If these are only the prefix, try String#start_with?:
require 'set'
legal_paths = Set['A/B/C', 'A/D/E', 'A/F/G']
files = Dir.glob('**/system.log').select do |fd|
fd.start_with?(*legal_paths)
end
Why not make use of the fact that you can specify these prefixes in the glob?
legal_paths = ['A/B/C', 'A/D/E', 'A/F/G']
files = Dir.glob("{#{legal_paths.join(',')}}/**/system.log")
Note though that if the legal_paths are input by the user, the above might not be secure as the user could traverse to parent directories using ...
A very common question on StackOverflow with regards to C++/R or C/R package integration is regarding the error in dyn.load(), e.g.
> ## within R
> Error in .Call("function_c") : C symbol name "function_c" not in load table
whereby function_c is some function in C like
SEXP function_c() {
Rprintf("Hello World!\n"); // manually changed
return(R_NilValue);
}
This error come sup due to many types of mistakes, e.g. incorrect compliation, misnamed functions, the user didn't use extern "C" for Cpp code, etc.
Question: Is there any way to view all "available" objects which the user could load via dyn.load() after compilation?
How about the following? I'm not sure it covers everything, but it should be close:
# manipulate search() to get all loaded packages
loadedPkgs = grep('^package:', search(), value = TRUE)
loadedPkgs = gsub('package:', '', loadedPkgs, fixed = TRUE)
# add names here to make the results of lapply pretty
names(loadedPkgs) = loadedPkgs
allCRoutines = lapply(loadedPkgs, function(pkg) {
# see: https://stackoverflow.com/questions/8696158/
pkg_env = asNamespace(pkg)
# this works at a glance
check_CRoutine = function(vname) {
'CallRoutine' %in% attr(get(vname, envir = pkg_env), 'class')
}
names(which(sapply(ls(envir = pkg_env, all = TRUE), check_CRoutine)))
})
The object is a bit long, so I'll just show for one package:
allCRoutines[['utils']]
# $utils
# [1] "C_crc64" "C_flushconsole" "C_menu" "C_nsl" "C_objectSize" "C_octsize" "C_processevents"
# [8] "C_sockclose" "C_sockconnect" "C_socklisten" "C_sockopen" "C_sockread" "C_sockwrite"
What I'm not sure of is that check_CRoutine catches everything we'd consider as relevant to your question. I'm also not sure this covers your main interest (whether these objects can succesfully be fed to dyn.load); perhaps the routines returned here could be passed to dyn.load with a try wrapper?
I'm coming from a Javascript background & I'm trying to understand how I need to structure/build a program with Reason/Ocaml's module system.
As an exercise let's say I want to write this piece of javascript in OCaml/Reason (will compile it back to js through js_of_ocaml)
var TeaType = new GraphQLObjectType({
name: 'Tea',
fields: () => ({
name: {type: GraphQLString},
steepingTime: {type: GraphQLInt},
}),
});
How should I design my program to accomplish this?
Should I make a module which takes another module to produce a GraphQLObjectType in js through js_of_ocaml?
How would I structure this type that backs a GraphQLObjectType?
Tea.re
let name = "Tea";
let fields = /* what type should I make for this? Tea is
just one of the many graphql-types I'll probably make */
I mean fields is a thunk which returns a map that contains an unknown amount of fields. (every graphqlobject has different fields)
To what type does this map in OCaml/Reason, do I need to make my own?
Just for you to feel the flavor of OCaml, the direct (syntactic) translation would be:
let tea_type = GraphQL.Object.{
name = "Tea";
fields = fun () -> QraphQL.Field.[{
name = GraphQL.Type.{name : GraphQL.string }
steeping_time = GraphQL.Type.{name : QraphQL.int }
}]
}
Basically, I mapped js objects to OCaml's records. There are also objects in OCaml with methods and inheritance, but I think that records are still a closer abstraction. The records can be seen as a named tuple, and, of course, can contain functions. Modules, are more heavy weight abstractions, that is also a collection of fields. Unlike records, modules may contain types, other modules, and basically any other syntactic construction. Since types are removed at compile time, the runtime representation of a module is absolutely the same as the representation of records. Modules also define namespaces. Since OCaml records are defined by the names of their fields, it is always useful to define each records in its own module, e.g.,
module GraphQL = struct
let int = "int"
let string = "string"
module Type = struct
type t = {
name : string
}
end
module Field = struct
type t = {
name : string;
steeping_time : Type.t
}
end
module Object = struct
type t = {
name : string;
fields : unit -> Field.t list
end
end
I was using QuasiQuotations in Yesod, and everything worked fine. BUT my file became very large and not nice to look at. Also, my TextEditor does not highlight this syntax correctly. That is why is split my files like so:
getHomeR :: Handler Html
getHomeR = do
webSockets chatApp
defaultLayout $ do
$(luciusFile "templates/chat.lucius")
$(juliusFile "templates/chat.julius")
$(hamletFile "templates/chat.hamlet")
If this is wrong, please do tell. Doing runghc myFile.hs throws many errors like this:
chat_new.hs:115:9:
Couldn't match expected type ‘t0 -> Css’
with actual type ‘WidgetT App IO a0’
The lambda expression ‘\ _render_ajFK
-> (shakespeare-2.0.7:Text.Css.CssNoWhitespace . (foldr ($) ...))
...’
has one argument,
but its type ‘WidgetT App IO a0’ has none
In a stmt of a 'do' block:
\ _render_ajFK
...
And this.
chat_new.hs:116:9:
Couldn't match type ‘(url0 -> [(Text, Text)] -> Text)
-> Javascript’
with ‘WidgetT App IO a1’
Expected type: WidgetT App IO a1
Actual type: JavascriptUrl url0
Probable cause: ‘asJavascriptUrl’ is applied to too few arguments
...
And also one for the HTML (Hamlet).
Thus, one per template.
It seems that hamletFile and others treat templates as self-contained, while yours are referencing something from each other. You can play with order of *File calls, or use widgetFile* from Yesod.Default.Util module:
$(widgetFileNoReload def "chat")
The Reload variant is useful for development - it would make yesod devel to watch for file changes and reload them.
I am working on an Ocsigen example (http://ocsigen.org/tuto/manual/macaque).
I get an error when trying to compile the program, as follows.
File "testDB.ml", line 15, characters 14-81 (end at line 18, character 4):
While finding quotation "table" in a position of "expr":
Available quotation expanders are:
svglist (in a position of expr)
svg (in a position of expr)
html5list (in a position of expr)
html5 (in a position of expr)
xhtmllist (in a position of expr)
xhtml (in a position of expr)
Camlp4: Uncaught exception: Not_found
My code is:
module Lwt_thread = struct
include Lwt
include Lwt_chan
end
module Lwt_PGOCaml = PGOCaml_generic.Make(Lwt_thread)
module Lwt_Query = Query.Make_with_Db(Lwt_thread)(Lwt_PGOCaml)
let get_db : unit -> unit Lwt_PGOCaml.t Lwt.t =
let db_handler = ref None in
fun () ->
match !db_handler with
| Some h -> Lwt.return h
| None -> Lwt_PGOCaml.connect ~database:"testbase" ()
let table = <:table< users (
login text NOT NULL,
password text NOT NULL
) >>
..........
I used eliom-destillery to generate the basic files.
I used "make" to compile the program.
I've tried many different things and done a google search but I can't figure out the problem. Any hints are greatly appreciated.
Generally speaking, the error message indicates that CamlP4 does not know the quotation you used, here table, which is used in your code as <:table< ... >>. The quotations can be added by CamlP4 extensions pa_xxx.cmo (or pa_xxx.cma) modules. Unless you made a typo of the quotation name, you failed to load an extension which provides it to CamlP4.
According to http://ocsigen.org/tuto/manual/macaque , Macaque (or its underlying libraries? I am not sure since I have never used it) provides the quotation table. So you have to instruct CamlP4 to load the corresponding extension. I believe the vanilla eliom-destillery is minimum for the basic eliom programming and does not cover for the extensions for Macaque.
Actually the document http://ocsigen.org/tuto/manual/macaque points out it:
We need to reference macaque in the Makefile :
SERVER_PACKAGE := macaque.syntax
This should be the CamlP4 syntax extension name required for table.