Fork me on GitHub
#beginners
<
2017-10-02
>
madstap00:10:00

@dfcarpenter Data structures are immutable. assoc doesn't change the data structure, it returns a new version of it. You need styles to be an argument in the loop as well.

Drew Verlee02:10:13

This seems like a rather Mundane topic, but does anyone have any good resources on file IO? I’m looking at the definition for and i’m feeling that i should be more comfortable with such a fundamental topic. It seems a file can mean many things, local-file, site, etc.. and its not even clear to me what i’m handed back. It seems like a lazy list? I have successful used this concept dozens of times but i’m wondering where people go to really wrap there heads around it.

noisesmith02:10:52

@drewverlee in the jvm a file is a file on disk

noisesmith02:10:09

io/reader returns a BufferedReader

+user=> ( ".bashrc")
#object[java.io.BufferedReader 0x70f59913 "java.io.BufferedReader@70f59913"]
+user=> (type *1)
java.io.BufferedReader

noisesmith02:10:46

if you want the abstraction that could be a file, or could be data from the network, or could be input from data in memory in a byte array, etc, what you want is InputStream

noisesmith02:10:38

@drewverlee regarding resources, on the jvm clojure IO is java IO, and it follows all the rules and conventions of the java classes, the functions in wrap up some of the more common operations for convenience but they don't offer a novel approach beyond what the jvm offers https://docs.oracle.com/javase/tutorial/essential/io/streams.html

noisesmith02:10:28

also you can look at the classes returned by the functions in http://clojure.java.io, they are all built into java and well documented

noisesmith02:10:33

in the java tutorial I linked above, this is where it starts talking about files (it covers a bunch of generic io oriented stuff first, as I mentioned before on the jvm a "file" is not an abstraction or general thing, it is always a file on your filesystem) https://docs.oracle.com/javase/tutorial/essential/io/fileio.html

Drew Verlee02:10:17

Thanks, a ton. that gives me a good starting place to look into stuff further!

dfcarpenter02:10:19

@madstap Thanks! that was it

bigdaddys1oth05:10:56

Hello to anyone who might be out there. I was trying to get better at Clojure (I suck at it now) by writing little functions that do simple things. I'm having some trouble with dotimes in the sense of this function I created

bigdaddys1oth05:10:31

the repl I started up says that the let statement is an unsupported binding form

bigdaddys1oth05:10:44

Basically I'm trying to decement a number by 0.333 a certain number of times. Nothing too fancy

bigdaddys1oth05:10:52

Ok it just returns a bunch of nils

chrisjd05:10:45

dotimes just evaluates the body n times and lets you know which iteration you’re on through the binding (`i` in your example). Remember that your data is immutable, too, so this may be a better way if you do want to use dotimes for it:

(defn dec-by-3rds [n x]
  (dotimes [i n]
    (println (- x (* i 0.333)))))

bigdaddys1oth05:10:09

Oh that makes sense

bigdaddys1oth05:10:08

doesn't dotimes allow for side effects?

bigdaddys1oth05:10:33

Oh I misundetstood what you said "immutable". My bad

bigdaddys1oth05:10:40

Is my method of learning Clojure fine? I find it somewhat more useful (for me, at least) than some of the 4clojure probelms.

chrisjd05:10:19

Only you know the answer to that. :) Experimenting with the REPL to understand how stuff works is what we all do, regardless of experience - it’s very instructive and lets you play and poke with things.

chrisjd05:10:49

Definitely the right thing to do.

bigdaddys1oth05:10:13

It's just I have trouble with the 4Clojure problems, and maybe that's just do to needing to understand a majority of Clojure's core functions better.

jumar06:10:29

@bigdaddys1oth you might want to look at https://github.com/functional-koans/clojure-koans/tree/master/src/koans - this could give you a good overview of basic clojure stuff. Another good resource is http://exercism.io which I liked a bit more than 4clojure. Moreover, ClojureDocs (http://clojuredocs.org/) is a good site to see some examples of usage of Clojure core functions + there is "SEE ALSO" section at the bottom which references the similar functions, e.g. http://clojuredocs.org/clojure.core/dotimes Finally, there are a few good books for Clojure beginners to get started: Many people like "Clojure for the Brave and True" and "Living Clojure". As regards to Clojure standard lib, there's a book Clojure Standard Library (in progress work): https://www.manning.com/books/clojure-standard-library

curlyfry07:10:55

@bigdaddys1oth Are you sorting the 4Clojure problems on difficulty?

Igor Garcia14:10:37

Hello. I'm not sure if it has been shared here already but I'd recommend this free course for everyone starting with Clojure: http://mooc.fi/courses/2014/clojure/

moogey17:10:01

I have this for getting fields from a pdf document

(defn get-fields [document]
  (->> document
       (.getDocumentCatalog)
       (.getAcroForm)
       (.getFields)))
If I wanted to be able to pass in any of those things to get the fields, what would be the clojure way to do that? matching the type in the function? multi-methods?

noisesmith17:10:07

you could use a multimethod or protocol - if what you are doing is directly dispatching on type, that’s exactly what protocols are for, though if you only have one operation (rather than a set of methods that go together) a multimethod can be simpler.

catamorphisms19:10:41

Does anyone know how I can get emacs cider to show test diffs?

sundarj21:10:19

have you tried #cider ?

danny21:10:46

not sure where I'm going wrong here...

danny21:10:46

(defn anagrams-for
  [word word-list]
  (filter #(apply (.contains word %) %) word-list))

(print (anagrams-for "first" ["one", "two", "strif"]))

danny21:10:49

Trying to test the given word against a list for possible anagrams

danny21:10:59

Pass in the word and word-list

danny21:10:26

Filter each word in the list by

danny21:10:53

1. calling apply to turn the word into a collection of letters

danny21:10:26

2. Returning a boolean from testing if each letter is contained in the word

danny21:10:19

When I run it I get this

CompilerException java.lang.ClassCastException: java.lang.Boolean cannot be cast to clojure.lang.IFn, compiling:(/home/danny/exercism/clojure/anagram/src/anagram.clj:7:1) 

danny21:10:54

I have a feeling the problem is in apply and passing the % argument reference

schmee21:10:54

@dannystanny01 apply takes a function as a first argument, but (.contains word %) returns a boolean

danny21:10:31

hm... okay

schmee21:10:38

gimmie a sec

danny21:10:18

it's okay, I'm gonna think out loud a little

danny21:10:51

so this also doesn't work, which I tried previously (filter #(apply .contains word %) word-list))

danny21:10:23

throws

CompilerException java.lang.RuntimeException: Unable to resolve symbol: .contains in this context, compiling:(/home/danny/exercism/clojure/anagram/src/anagram.clj:5:12) 
So .contains isn't a function?

schmee21:10:55

not in the usual sense, it is a Java method

schmee21:10:11

they behave a little differently in certain contexts

schmee21:10:44

you can wrap it in a regular fn like this: (fn [thing x] (.contains thing x))

danny22:10:45

like so?

(filter #(apply (fn [letter] (.contains word letter)) word-list)))

danny22:10:03

that at least runs lol

schmee22:10:29

(defn anagrams-for
  [word word-list]
  (let [letters (sort (seq word))]
    (filter #(= letters (sort (seq %))) word-list)))

schmee22:10:28

you can def make your version work to

schmee22:10:43

try using seq instead of apply to turn a string into a seq of chars and go from there 🙂

danny22:10:40

alright, so I'm definitely a little lost on your answer, but I ran it and it does indeed work. Still need to try and figure out my version for learnings. So I replaced apply with seq as you suggested (as well as the different inner anon fn)

(defn anagrams-for
  [word word-list]
  (filter #(seq (fn [letter] (.contains word letter)) word-list)))

danny22:10:36

Now this is returning an object in mem

#object[clojure.core$filter$fn__4808 0x14de7968 clojure.core$filter$fn__4808@14de7968]
I'm guessing because filter returns a lazy seq and I still need to call it properly.. which I'm apparently not doing?

schmee22:10:44

are you using a REPL?

danny22:10:02

yea, Atom with ProtoREPL running on the file

schmee22:10:24

nice, I suggest working from the inside out and trying one thing at a time

schmee22:10:42

example: (.contains "asdf" "a") works, so now you want to do that for a sequence of chars, so you need some kind of loop

schmee22:10:39

user=> (map #(.contains "asdf" (str %)) (seq "asdx"))
(true true true false)

schmee22:10:02

and then you want to check if they are all true, so you turn to http://clojuredocs.org and search for the appropriate function 😄

danny22:10:32

oh the docs are open lol

schmee22:10:39

very often in clojure, there is a function in clojure.core that does what you want 🙂

danny22:10:28

yea, i just have a hard time navigating as a total noob. verrrry different from my previous languages

schmee22:10:07

I feel you, I was completely lost the first few days 😄

danny22:10:20

but of course the biggest problem is just being new haha

schmee22:10:24

have you gone through any tutorials?

schmee22:10:35

diving right in without knowing the basics can be tough

danny22:10:50

I got about halfway through Clojure4Brave before I couldn't stand the examples anymore

danny22:10:16

then started on 4clojure, but that wasn't great for learning because it was mostly code golf from other users

schmee22:10:34

I remember https://aphyr.com/tags/Clojure-from-the-ground-up being helpful when I started out

danny22:10:48

so i spent time getting to know thee environment more and now i'm enjoying exercism

danny22:10:04

I'll check that out, thanks

schmee22:10:39

my one tip is to work from the inside out

schmee22:10:03

that is, try each piece separately at the REPL and make sure it does what you think before putting it together with something else

danny22:10:21

I get over-eager lol

danny22:10:25

good advice though

schmee22:10:40

to continue on my example above:

user=> (every? true? (map #(.contains "asdf" (str %)) (seq "asdx")))
false

schmee22:10:59

so if you turn that into a function, you have something that checks if each char of a string is in another char

schmee22:10:17

then you want to do that for each word in a list of words

schmee22:10:19

sorry if my examples kinda suck, it’s really hard to just hint at a solution without giving it away completely 😄

danny22:10:02

No worries, so as a quick question, so far in your examples you've chosen map over filter, any reason for that in this situation? Or just so as not to give me an answer 🙂

danny22:10:15

as the looping mechanism*

schmee22:10:35

user=> (map #(.contains "asdf" (str %)) (seq "asdx"))
(true true true false)
user=> (filter #(.contains "asdf" (str %)) (seq "asdx"))
(\a \s \d)

schmee22:10:48

they way I think about it is “is the character in the string, yes or no?“, therefore I want map

schmee22:10:44

you could do another variant with filter if you count th chars in the word, and in the filtered word. if they are anagrams, the should be the same

danny22:10:03

Filter works on booleans, right?

danny22:10:29

filter -> some collection -> return item if item True

danny22:10:32

psuedo-code

danny22:10:36

obviously

danny22:10:07

so my thought process is like the outside in, filter on the collection being fed to the function

danny22:10:52

with the inner contents of filter applying some function to test for all letters being in the word

seancorfield22:10:56

Since you're working with side-effects, you don't really want map at all, you want doseq -- and that will make it easier to work on parts of the file.

seancorfield22:10:56

(doseq [line (line-seq reader)] (do-filter line)) instead of your (doall (map ...)) -- so now you can do take/`drop` on the (line-seq reader) part easily enough

seancorfield22:10:56

map is if you want to transform a sequence -- and use the result of that transformation. doseq is for when you want to process a sequence for side-effects (and have no returned value).