Good morning everyone,
To finish this project i needs your help, again.
So now i'm trying to create two functions to reading/writing files in lisp.
this is the description how the functions must work
(json-load filename) -> JSON
(json-write JSON filename) -> filename
The json-load function opens the file filename returns a JSON object (or generates an error). If
filename does not exist the function generates an error. The suggestion is to read the whole file in one
string and then to call json-parse.
The json-write function writes the JSON object to the filename file in JSON syntax. If
filename does not exist, it is created and if it exists it is overwritten. Of course it is expected that
CL-PROMPT> (json-load (json-write '(json-obj # | stuff | #) "foo.json"))
(json-obj # | stuff | #)
this is my json-load function
(defun json-load (filename)
(with-open-file (file-stream filename)
(let ((file-contents (make-string (file-length file-stream))))
(read-sequence file-contents file-stream)
file-contents)) (json-parse (file-contents)))
but it not working
i need some help to write function too.
thanks guys
edit 1:
(defun json-load (filename)
(with-open-file (in filename
:direction :input
:if-does-not-exist :error)
(file-get-contents filename))
(json-parse filename))
(defun file-get-contents (filename)
(with-open-file (stream filename)
(let ((contents (make-string (file-length stream))))
(read-sequence contents stream)
contents)))
so the function should be not far away to be correct but the problem, i think, is the file-get-contents function.
I think that because if i run this function the output is
"\"{\\\"nome\\\" : \\\"Arthur\\\",\\\"cognome\\\" : \\\"Dent\\\"}\""
and so the json-parse does not recognize json-object anymore.
Any ideas?
edit 2:
i try both functions but with the same result. if i call json-parse with the same json-object in the file it's all right but if i call json-load lisp respond me with my own error message "undefined JSON object (json-parse)".
Why?
Edit 3:
This is json-write function but, for now, it doesn't work.
(defun json-write (json filename)
(with-open-file (out filename
:direction :output
:if-exists :overwrite
:if-does-not-exist :create)
(pprint (json out))))
so the description at the beginning of the post says that the json-write function writes JSON object to the filename file in JSON syntax.
Now, 2 questions
1) it's my function partially correct?
2) how can i write a Json object in Json syntax?
Thanks
I'm working on the same project, hopefully the professors don't mind us sharing info ;)
This is the approach I took:
(defun json-load (filename)
(with-open-file (in filename
:direction :input
:if-does-not-exist :error)
(multiple-value-bind (s) (make-string (file-length in))
(read-sequence s in)
(json-parse s))))
Remember that read-sequence overwrites the given sequence, in this case s. I'm using multiple-value-bind simply so that I don't have to use neither variable declarations nor a lambda function (Although it is just a less idiomatic version of (let ((v form)) ...)), as #tfb pointed out).
Related
Good morning i need help to write this function in lisp.
this is the description.
The json-write function writes the JSON object to the filename file in JSON syntax. If
filename does not exist, it is created and if it exists it is overwritten. Of course it is expected that
CL-PROMPT> (json-load (json-write '(json-obj # | stuff | #) "foo.json"))
(json-obj # | stuff | #)
and this is my function but it isn't correct
(defun json-write (json filename)
(with-open-file (out filename
:direction :output
:if-exists :overwrite
:if-does-not-exist :create)
(pprint (json out))))
thanks
Edit 1:
i try to write var json (that is a json object) into filename.
but pprint doesn't write anything to filename
Edit 2:
(defun json-write (json filename)
(with-open-file (out filename
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
(cond
((equal (first json) ‘json-array) (write-arr json))
((equal (first json) ‘json-obj) (write-obj json)))))
so i try this now
if json is json-array lisp call write-arr json
if json is json-obj call write-obj
so my idea is that write-arr trasform
(json-array 1 2 3) in `"[1, 2, 3]"` to make it parsable
and write-obj trasform
(json-obj ("nome" "Arthur") ("cognome" "Dent"))
in
"{\"nome\" : \"Arthur\",
\"cognome\" : \"Dent\"}"
and then write everythings into filename with format stream.
how can i format (json-array 1 2 3) in "[1, 2, 3]".
with format function? and then calling recursively even this function?
thank you
When you write (pprint (json out)) you are trying to call a global function called json. I think you mean (pprint json out).
Now here is roughly how to write a simple json printer:
(defun write-json (object stream)
(etypecase object
(number (format stream “~a” object))
(string (print object stream))
(null (format stream “null”))
(cons
(ecase (car object)
(json-array
(write-char #\[ stream)
(loop for (x . r) on (cdr object)
do (write-json x stream)
(when r (write-char #\, stream)))
(write-char #\] stream))))))
There are plenty of gaps to fill in. And note that this will print strings wrong if they contain new lines. And you probably want to do something less stupid for printing numbers.
Here is how I would implement a json pretty printer with CLOS:
(defvar *json-pretty* nil)
(defvar *json-indent-level* 0)
(defvar *json-indent-spaces* 2)
(defun json-fresh-line (stream)
(if *json-pretty*
(progn
(fresh-line stream)
(loop repeat (* *json-indent-level* *json-indent-spaces*)
do (write-char #\Space stream)))
(write-char #\Space stream))
(defgeneric write-json (object stream))
(defgeneric write-json-collection (type data stream))
(defmethod write-json ((object cons) stream)
(write-json-collection (car object) (cdr object) stream))
(defmethod write-json-collection ((tag (eql json-array)) data stream)
...)
There are plenty of methods left to write.
I'm writing a lisp app to create 2D patterns for a CNC cutter. I have an Excel program that outputs 3-10 short lisp subroutines for individual pieces associated with each pattern, and I can get any number of these subs to load inside my "while" loop and draw the piece, but none of the methods I can get working to create .dxf files from the drawings generated by one of the pattern subs will let me resume the loop. If I pull out the dxfout and erase steps and just let them all draw on top of one another, it works like a charm.
(defun c:CreateDXF (/ owd ofd sdate)
(setq owd (acet-file-cwd))
(acet-file-chdir "P:\\")
(setq ofd (getvar "filedia"))
(setvar "filedia" 0)
(setq sdate (getstring "\nEnter the order start date in YYYYMMDD format: "))
(setq fpath (strcat "P:\\LSP\\" sdate))
(setq wopath (acet-ui-pickdir "Select Work Order Folder" fpath))
(setq flist (vl-directory-files wopath "*.lsp" 1))
(while (> (length flist) 0)
(setq fname (car flist))
(setq wfile (strcat wopath "\\" fname))
(vl-file-rename wfile "P:\\LSP\\temp.lsp")
(load "P:\\LSP\\temp.lsp")
(vl-file-rename "P:\\LSP\\temp.lsp" wfile)
(setq savepath (strcat "P:\\DXF\\" sdate))
(setq savename (strcat (vl-filename-base wfile) ".dxf"))
(setq patt (ssget "x"))
(command "_.dxfout" savepath "_Objects" patt "" "_Version" "2013" "16" "" "")
(command "erase" "all" "")
(setq flist (cdr flist))
);while
(acet-file-chdir owd)
(setvar "filedia" ofd)
(alert "Done")
(princ)
);defun
Running this as written hangs up at the first dxfout step. I can reset the program through the lisp editor, and then file appears in the output directory and the dxf comes up in a new tab, but obviously that exits the loop without processing the rest of the pieces.
Am I missing something obvious? Would it be better to draw all of the pattern pieces in the same drawing as named entities and then batch out each entity at the end?
It might be easier to approach this from outside of AutoCAD. Maybe using a PowerShell script to fetch the .dwg files list, open AutoCAD, then loop through the drawing list, export the .dxf, close the .dwg and do the next, then close AutoCAD.
My main goal is to redirect stderr to a file.
I got hold of the following code snippet...
catchOutput :: IO a -> IO (res, String)
catchOutput f = do
tmpd <- getTemporaryDirectory
(tmpf, tmph) <- openTempFile tmpd "haskell_stderr"
stderr_dup <- hDuplicate stderr
hDuplicateTo tmph stderr
hClose tmph
res <- f
hDuplicateTo stderr_dup stderr
str <- readFile tmpf
removeFile tmpf
return (res, str)
I hoped to make this more general and pass any function and argument list to catchOutput and get the function result as well as message written to stderr (if any).
I thought that an argument list of type [Data.Dynamic] might work but I failed to retrieve the function result with
res <- Data.List.foldl (f . fromDyn) Nothing $ args
Is this even possible? Help will be greatly appreciated.
There is not reason to use Data.Dynamic. You already know type the return type of f, it's a so you can use just that, i.e.
catchOutput :: IO a -> IO (a, String)
Note though, that there some significant issues with your approach:
By redirecting stderr to a file, this will also affect all other concurrent threads. So you could possibly get unrelated data sent to the temporary file.
If an exception is thrown while stderr is redirected, the original stderr will not be restored. Any operation between the two hDuplicateTo lines (hClose and f in this case) could possibly throw an exception, or the thread may receive an asynchronous exception. For this reason, you have to use something like bracket to make your code exception safe.
I've just discovered the shr package in emacs 24.5.1
i.e.
C-x C-f anyfile.html
M-x shr-render-buffer
Looks really good - just what I was after
Can I automate emacs to call shr-render-buffer when I open any .htm or .html file?
UPDATE
I've tried adding the following to my .emacs:
(add-to-list 'auto-mode-alist '("[.]htm$" . shr-render-buffer))
(add-to-list 'auto-mode-alist '("[.]html$" . shr-render-buffer))
but I get the error:
File mode specification error: (void-function shr-render-buffer)
The html file then gets opened in Fundamental mode and it looks even worse than HTML mode
It seems you want to run the function shr-render-buffer automatically once a html file is opened. As you said, the mode for .htm/.html is html-mode by default, you can add the function invocation to the html-mode-hook, such as:
(add-hook 'html-mode-hook '(lambda() (shr-render-buffer (current-buffer))))
As #lawlist pointed, put it after (require 'shr).
As this is emacs, the hardest part of doing what you want is deciding on what is the best approach. This largely depends on personal taste/workflows. I would highly recommend looking at the browse-url package in more detail. One thing I use is a function which allows me to switch between using eww or my default system browser - this means I can easily render web content either in emacs or in chrome/safari/whatever.
Some years ago, I wrote a utility which would allow me to view a number of different file formats, including rendered html, in emacs. I rarely use this now as doc-view has pretty much replaced most of this functionality and is much better. However, it does show how you can use defadvice to modify the view-file function so that id does different things depending on the file type. Note that as this is old emacs code and emacs has improved, there are probably better ways of doing this now. I also know that the 'advice' stuff has been re-worked, but this legacy stuff still works OK. Should get you started. Note that the functionality for MS doc, docx, pdf etc relies on external executables.
My preferred workflow would be to write a function which allows me to reset the browse-url-browser-function to either eww-browse-url or browse-url-default-browser and bind that to a key. I can then choose to display the html in emacs or the external browser and leverage of all the work already done in browse-url.
(require 'custom)
(require 'browse-url)
;; make-temp-file is part of apel prior to emacs 22
;;(static-when (= emacs-major-version 21)
;; (require 'poe))
(defgroup txutils nil
"Customize group for txutils."
:prefix "txutils-"
:group 'External)
(defcustom txutils-convert-alist
'( ;; MS Word
("\\.\\(?:DOC\\|doc\\)$" doc "/usr/bin/wvText" nil nil nil nil nil)
;; PDF
("\\.\\(?:PDF\\|pdf\\)$" pdf "/usr/bin/pdftotext" nil nil nil nil nil)
;; PostScript
("\\.\\(?:PS\\|ps\\)$" ps "/usr/bin/pstotext" "-output" t nil nil nil)
;; MS PowerPoint
("\\.\\(?:PPT\\|ppt\\)$" ppt "/usr/bin/ppthtml" nil nil nil t t))
"*Association for program convertion.
Each element has the following form:
(REGEXP SYMBOL CONVERTER SWITCHES INVERT REDIRECT-INPUT REDIRECT-OUTPUT HTML-OUTPUT)
Where:
REGEXP is a regexp to match file type to convert.
SYMBOL is a symbol to designate the fyle type.
CONVERTER is a program to convert the fyle type to text or HTML.
SWITCHES is a string which gives command line switches for the conversion
program. Nil means there are no switches needed.
INVERT indicates if input and output program option is to be
inverted or not. Non-nil means to invert, that is, output
option first then input option. Nil means do not invert,
that is, input option first then output option.
REDIRECT-INPUT indicates to use < to direct input from the input
file. This is useful for utilities which accept input
from stdin rather than a file.
REDIRECT-OUTPUT indicates to use > to direct output to the output
file. This is useful for utilities that only send output to
stdout.
HTML-OUTPUT Indicates the conversion program creates HTML output
rather than plain text."
:type '(repeat
(list :tag "Convertion"
(regexp :tag "File Type Regexp")
(symbol :tag "File Type Symbol")
(string :tag "Converter")
(choice :menu-tag "Output Option"
:tag "Output Option"
(const :tag "None" nil)
string)
(boolean :tag "Invert I/O Option")
(boolean :tag "Redirect Standard Input")
(boolean :tag "Redirect Standard Output")
(boolean :tag "HTML Output")))
:group 'txutils)
(defun txutils-run-command (cmd &optional output-buffer)
"Execute shell command with arguments, putting output in buffer."
(= 0 (shell-command cmd (if output-buffer
output-buffer
"*txutils-output*")
(if output-buffer
"*txutils-output*"))))
(defun txutils-quote-expand-file-name (file-name)
"Expand file name and quote special chars if required."
(shell-quote-argument (expand-file-name file-name)))
(defun txutils-file-alist (file-name)
"Return alist associated with file of this type."
(let ((al txutils-convert-alist))
(while (and al
(not (string-match (caar al) file-name)))
(setq al (cdr al)))
(if al
(cdar al)
nil)))
(defun txutils-make-temp-name (orig-name type-alist)
"Create a temp file name from original file name"
(make-temp-file (file-name-sans-extension
(file-name-nondirectory orig-name)) nil
(if (nth 7 type-alist)
".html"
".txt")))
(defun txutils-build-cmd (input-file output-file type-alist)
"Create the command string from conversion alist."
(let ((f1 (if (nth 3 type-alist)
output-file
input-file))
(f2 (if (nth 3 type-alist)
input-file
output-file)))
(concat
(nth 1 type-alist)
(if (nth 2 type-alist) ; Add cmd line switches
(concat " " (nth 2 type-alist)))
(if (nth 4 type-alist) ; redirect input (which may be output
(concat " < " f1) ; if arguments are inverted!)
(concat " " f1))
(if (nth 5 type-alist) ; redirect output (see above comment)
(concat " > " f2)
(concat " " f2)))))
(defun txutils-do-file-conversion (file-name)
"Based on file extension, convert file to text. Return name of text file"
(interactive "fFile to convert: ")
(let ((f-alist (txutils-file-alist file-name))
output-file)
(when f-alist
(message "Performing file conversion for %s." file-name)
(setq output-file (txutils-make-temp-name file-name f-alist))
(message "Command: %s" (txutils-build-cmd file-name output-file f-alist))
(if (txutils-run-command
(txutils-build-cmd (txutils-quote-expand-file-name file-name)
(txutils-quote-expand-file-name
output-file) f-alist))
output-file
file-name))))
(defadvice view-file (around txutils pre act comp)
"Perform file conversion or call web browser to view contents of file."
(let ((file-arg (ad-get-arg 0)))
(if (txutils-file-alist file-arg)
(ad-set-arg 0 (txutils-do-file-conversion file-arg)))
(if (string-match "\\.\\(?:HTML?\\|html?\\)$" (ad-get-arg 0))
(browse-url-of-file (ad-get-arg 0))
ad-do-it)))
(provide 'init-text-convert)
hello I am making some word searching program
for example
when "text.txt" file contains "foo foos foor fo.. foo fool"
and search "foo"
then only number 2 printed
and search again and again
but I am haskell beginner
my code is here
:module +Text.Regex.Posix
putStrLn "type text file"
filepath <- getLine
data <- readFile filepath
--1. this makes <interactive>:1:1: parse error on input `data' how to fix it?
parsedData =~ "[^- \".,\n]+" :: [[String]]
--2. I want to make function and call it again and again
searchingFunc = do putStrLn "search for ..."
search <- getLine
result <- map (\each -> if each == search then count = count + 1) data
putStrLn result
searchingFunc
}
sorry for very very poor code
my development environment is Windows XP SP3 WinGhci 1.0.2
I started the haskell several hours ago sorry
thank you very much for reading!
edit: here's original scheme code
thanks!
#lang scheme/gui
(define count 0)
(define (search str)
(set! count 0)
(map (λ (each) (when (equal? str each) (set! count (+ count 1)))) data)
(send msg set-label (format "~a Found" count)))
(define path (get-file))
(define port (open-input-file path))
(define data '())
(define (loop [line (read-line port)])
(when (not (eof-object? line))
(set! data (append data
(regexp-match* #rx"[^- \".,\n]+" line)))
(loop)))
(loop)
(define (cb-txt t e) (search (send t get-value)))
(define f (new frame% (label "text search") (min-width 300)))
(define txt (new text-field% (label "type here to search") (parent f) (callback (λ (t e) (cb-txt t e)))))
(define msg (new message% (label "0Found ") (parent f)))
(send f show #t)
I should start by iterating what everyone would (and should) say: Start with a book like Real World Haskell! That said, I'll post a quick walkthrough of code that compiles, and hopefully does something close to what you originally intended. Comments are inline, and hopefully should illustrate some of the shortcomings of your approach.
import Text.Regex.Posix
-- Let's start by wrapping your first attempt into a 'Monadic Action'
-- IO is a monad, and hence we can sequence 'actions' (read as: functions)
-- together using do-notation.
attemptOne :: IO [[String]]
-- ^ type declaration of the function 'attemptOne'
-- read as: function returning value having type 'IO [[String]]'
attemptOne = do
putStrLn "type text file"
filePath <- getLine
fileData <- readFile filePath
putStrLn fileData
let parsed = fileData =~ "[^- \".,\n]+" :: [[String]]
-- ^ this form of let syntax allows us to declare that
-- 'wherever there is a use of the left-hand-side, we can
-- substitute it for the right-hand-side and get equivalent
-- results.
putStrLn ("The data after running the regex: " ++ concatMap concat parsed)
return parsed
-- ^ return is a monadic action that 'lifts' a value
-- into the encapsulating monad (in this case, the 'IO' Monad).
-- Here we show that given a search term (a String), and a body of text to
-- search in, we can return the frequency of occurrence of the term within the
-- text.
searchingFunc :: String -> [String] -> Int
searchingFunc term
= length . filter predicate
where
predicate = (==)term
-- ^ we use function composition (.) to create a new function from two
-- existing ones:
-- filter (drop any elements of a list that don't satisfy
-- our predicate)
-- length: return the size of the list
-- Here we build a wrapper-function that allows us to run our 'pure'
-- searchingFunc on an input of the form returned by 'attemptOne'.
runSearchingFunc :: String -> [[String]] -> [Int]
runSearchingFunc term parsedData
= map (searchingFunc term) parsedData
-- Here's an example of piecing everything together with IO actions
main :: IO ()
main = do
results <- attemptOne
-- ^ run our attemptOne function (representing IO actions)
-- and save the result
let searchResults = runSearchingFunc "foo" results
-- ^ us a 'let' binding to state that searchResults is
-- equivalent to running 'runSearchingFunc'
print searchResults
-- ^ run the IO action that prints searchResults
print (runSearchingFunc "foo" results)
-- ^ run the IO action that prints the 'definition'
-- of 'searchResults'; i.e. the above two IO actions
-- are equivalent.
return ()
-- as before, lift a value into the encapsulating Monad;
-- this time, we're lifting a value corresponding to 'null/void'.
To load this code, save it into a .hs file (I saved it into 'temp.hs'), and run the following from ghci. Note: the file 'f' contains a few input words:
*Main Text.Regex.Posix> :l temp.hs
[1 of 1] Compiling Main ( temp.hs, interpreted )
Ok, modules loaded: Main.
*Main Text.Regex.Posix> main
type text file
f
foo foos foor fo foo foo
The data after running the regex: foofoosfoorfofoofoo
[1,0,0,0,1,1]
[1,0,0,0,1,1]
There is a lot going on here, from do notation to Monadic actions, 'let' bindings to the distinction between pure and impure functions/values. I can't stress the value of learning the fundamentals from a good book!
Here is what I made of it. It doesn't does any error checking and is as basic as possible.
import Text.Regex.Posix ((=~))
import Control.Monad (when)
import Text.Printf (printf)
-- Calculates the number of matching words
matchWord :: String -> String -> Int
matchWord file word = length . filter (== word) . concat $ file =~ "[^- \".,\n]+"
getInputFile :: IO String
getInputFile = do putStrLn "Enter the file to search through:"
path <- getLine
readFile path -- Attention! No error checking here
repl :: String -> IO ()
repl file = do putStrLn "Enter word to search for (empty for exit):"
word <- getLine
when (word /= "") $
do print $ matchWord file word
repl file
main :: IO ()
main = do file <- getInputFile
repl file
Please start step by step. IO in Haskell is hard, so you shouldn't start with file manipulation. I would suggest to write a function that works properly on a given String. That way you can learn about syntax, pattern matching, list manipulation (maps, folds) and recursion without beeing distracted by the do notation (which kinda looks imperative, but isn't, and really needs a deeper understanding).
You should check out Learn you a Haskell or Real World Haskell to get a sound foundation. What you do now is just stumbling in the dark - which may work if you learn languages that are similar to the ones you know, but definitely not for Haskell.