chat-gpt test
This commit is contained in:
parent
d32002c573
commit
08a1f190d1
2 changed files with 255 additions and 1 deletions
|
@ -75,7 +75,7 @@ figure img { width: 100%; }
|
||||||
|
|
||||||
img { max-width: 100%; border: solid; }
|
img { max-width: 100%; border: solid; }
|
||||||
li p { margin: 0; padding: 0; }
|
li p { margin: 0; padding: 0; }
|
||||||
li > img, p > img { max-height: 1.5em; vertical-align: middle; }
|
li > img, p > img { max-height: 1.5em; vertical-align: middle; border: none; padding: none; margin: none; }
|
||||||
abbr {border-bottom: dotted 1px;}
|
abbr {border-bottom: dotted 1px;}
|
||||||
sup, sub {
|
sup, sub {
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
|
|
254
src/posts/0023-my-first-chatgpt-exchange/index.org
Normal file
254
src/posts/0023-my-first-chatgpt-exchange/index.org
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
#+title: My first ChatGPT exchange
|
||||||
|
#+description: My first interaction with ChatGPT about Clojure and Monads.
|
||||||
|
#+keywords: machine-learning ai gpt
|
||||||
|
#+author: Yann Esposito
|
||||||
|
#+email: yann@esposito.host
|
||||||
|
#+date: [2022-12-11 Sun]
|
||||||
|
#+lang: en
|
||||||
|
#+options: auto-id:t
|
||||||
|
#+startup: showeverything
|
||||||
|
|
||||||
|
#+macro: logo @@html:<img src="/logo.svg" alt="me" style="width:1.5em;filter:none;"/>@@
|
||||||
|
|
||||||
|
* The first few questions for ChatGPT
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: the-first-few-questions-for-chatgpt
|
||||||
|
:END:
|
||||||
|
|
||||||
|
I finally opened an account to beta-test ChatGPT.
|
||||||
|
I must say, I am quite impressed.
|
||||||
|
I asked it a few questions that I could have asked during an interview.
|
||||||
|
To my surprise, the answer given was, while wrong, believable enough to kind of
|
||||||
|
sneak the answer as right up to some imprecision.
|
||||||
|
Like if you squint enough, it could pass, but if you pay attention it is clearly
|
||||||
|
false.
|
||||||
|
|
||||||
|
So yes, mainly ChatGPT in this interaction was quite good at being convincing.
|
||||||
|
This is the same kind of impression you have from looking at AI generated images.
|
||||||
|
At first sight everything seems fine, but if you start looking to the details, many
|
||||||
|
things are off.
|
||||||
|
|
||||||
|
So here is the full interaction, I'll let the attentive reader find the
|
||||||
|
technical problems:
|
||||||
|
|
||||||
|
|
||||||
|
{{{logo}}} Can you write a clojure function that will reverse any string provided to it.
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
|
||||||
|
*ChatGPT*: Sure, here's a possible implementation of a function that reverses a string in Clojure:
|
||||||
|
|
||||||
|
#+begin_src clojure
|
||||||
|
(defn reverse-string [s]
|
||||||
|
(apply str (reverse (seq s))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
This function takes a strings as input, converts it to a sequence of characters
|
||||||
|
using the ~seq~ function, reverses this sequence using the reverse function, and
|
||||||
|
then converts the resulting sequence back to a string using the ~apply~ and ~str~
|
||||||
|
functions.
|
||||||
|
|
||||||
|
Here's an example of how you can use this function:
|
||||||
|
#+begin_src clojure
|
||||||
|
user=> (reverse-string "hello world")
|
||||||
|
"dirow olleh"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
Note that this function only works
|
||||||
|
for strings that contain characters in the Unicode Basic Multilingual Plane
|
||||||
|
(BMP), since the ~seq~ function only works on strings that contain characters in
|
||||||
|
this range.
|
||||||
|
If you need to reverse strings that contain characters outside of the BMP, you
|
||||||
|
can use the ~string-seq~ function instead of ~seq~ to convert the string to a
|
||||||
|
sequence of characters.
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
{{{logo}}} How would this function react if instead of string you provide an integer?
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
*ChatGPT:* If you provide an integer as input to the ~reverse-string~ function instead of a
|
||||||
|
string, the function will fail with a ~ClassCastException~ because the ~seq~
|
||||||
|
function only works on strings, and you cannot convert an integer to a string in
|
||||||
|
a straightforward way in Clojure.
|
||||||
|
The ~seq~ function expects its input to be a string or a collection, such as a
|
||||||
|
vector or a list, and when you try to pass an integer to it, it will try to
|
||||||
|
convert the integer to a string by calling the ~str~ function on it.
|
||||||
|
However, since ~str~ only works on strings and collections, and not on numbers,
|
||||||
|
this will result in a ~ClassCastException~.
|
||||||
|
|
||||||
|
Here's an example of what will happen if you try to pass an integer to the reverse-string function:
|
||||||
|
|
||||||
|
#+begin_src clojure
|
||||||
|
user=> (reverse-string 12345)
|
||||||
|
ClassCastException clojure.lang. Numbers cannot be cast to
|
||||||
|
clojure.lang. IFn clojure.core/seq (core.clj:136)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
To avoid this error, you can either make sure that the input to the
|
||||||
|
~reverse-string~ function is always a string, or you can modify the function to
|
||||||
|
handle other types of input, such as integers, by first converting them to
|
||||||
|
strings using the ~str~ function.
|
||||||
|
For example, you could write the ~reverse-string~ function like this to handle
|
||||||
|
both strings and integers as input:
|
||||||
|
|
||||||
|
#+begin_src clojure
|
||||||
|
(defn reverse-string [s]
|
||||||
|
(let [s (if (string? s) s (str s))]
|
||||||
|
(apply str (reverse (seq s)))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
With this version of the function, if you pass an integer as input, the function
|
||||||
|
will convert it to a string using the ~str~ function before calling the ~seq~
|
||||||
|
function on it, so the ~seq~ function will be able to work with the input.
|
||||||
|
Here's an example of how you can use this modified version of the
|
||||||
|
~reverse-string~ function:
|
||||||
|
|
||||||
|
#+begin_src clojure
|
||||||
|
user-> (reverse-string "hello world")
|
||||||
|
"dlrow olleh"
|
||||||
|
|
||||||
|
user=> (reverse-string 12345)
|
||||||
|
"54321"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Note that the modified version of the function will also work for other types of
|
||||||
|
input that can be converted to strings using the ~str~ function, such as floats
|
||||||
|
and booleans.
|
||||||
|
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
{{{logo}}} How would you use the concept of the Maybe monad in Haskell in this clojure function?
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
*ChatGPT*: The Maybe monad in Haskell is a way to represent computations that may or may
|
||||||
|
not have & p a result, and it provides a way to compose these computations in a
|
||||||
|
safe and predictable way.
|
||||||
|
In Clojure, the Maybe monad is usually implemented as a ~Option~ type, which has
|
||||||
|
two possible values: ~Some~ and ~None~
|
||||||
|
|
||||||
|
In the context of the ~reverse-string~ function, you could use the ~Option~ type
|
||||||
|
to represent the possibility that the input to the function might not be a
|
||||||
|
string, in which case the function would return ~None~ instead of a reversed
|
||||||
|
string.
|
||||||
|
Here's an example of how you could use the ~Option~ type to modify the
|
||||||
|
~reverse-string~ function to handle the case where the input is not a string:
|
||||||
|
|
||||||
|
#+begin_src clojure
|
||||||
|
(defn reverse-string [s]
|
||||||
|
(if (string? s)
|
||||||
|
(Some (apply str (reverse (seq s))))
|
||||||
|
None))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
With this version of the ~reverse-string~ function, if the input is a string, the
|
||||||
|
function will return a ~Some~ value containing the reversed string, and if the
|
||||||
|
input is not a string, the function will return a ~None~ value.
|
||||||
|
This allows the caller of the function to handle the case where the input is not
|
||||||
|
a string in a predictable and safe way.
|
||||||
|
|
||||||
|
Here's an example of how you can use this modified version of the ~reverse-string~
|
||||||
|
function:
|
||||||
|
|
||||||
|
#+begin_src clojure
|
||||||
|
user=> (reverse-string "hello world")
|
||||||
|
|
||||||
|
Some "dlrow olleh"
|
||||||
|
user=> (reverse-string 12345)
|
||||||
|
None
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Note that the Option type in Clojure does not provide the same syntactic sugar
|
||||||
|
for composing computations as the Maybe monad in Haskell, so you cannot use the
|
||||||
|
~>>=~ operator to chain calls to the ~reverse-string~ function in the same way you
|
||||||
|
can in Haskell.
|
||||||
|
However, you can still use the ~Option~ type to represent computations that may
|
||||||
|
or may not have a result, and you can use the ~match~ or ~case~ forms to pattern
|
||||||
|
match on the ~Option~ values and handle the different cases in a predictable and
|
||||||
|
safe way.
|
||||||
|
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
{{{logo}}} How would you implement Option in clojure?
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
*ChatGPT*:
|
||||||
|
In Clojure, the ~Option~ type is typically implemented as a sealed protocol,
|
||||||
|
which is a type of polymorphic type that defines a set of concrete types that
|
||||||
|
implement the protocol.
|
||||||
|
|
||||||
|
The ~Option~ protocol typically defines two concrete types: ~Some~, which represents
|
||||||
|
a computation that has a result, and ~None~, which represents a computation that
|
||||||
|
does not have a result.
|
||||||
|
|
||||||
|
Here's an example of how you could define the ~Option~ protocol and the ~Some~ and
|
||||||
|
~None~ types in Clojure:
|
||||||
|
|
||||||
|
#+begin_src clojure
|
||||||
|
(defprotocol Option
|
||||||
|
(map [o f])
|
||||||
|
(flat-map [o f]))
|
||||||
|
|
||||||
|
(deftype Some [x]
|
||||||
|
Option
|
||||||
|
(map [o f] (Some (f x)))
|
||||||
|
(flat-map [o f] (f x)))
|
||||||
|
|
||||||
|
(deftype None [])
|
||||||
|
Option
|
||||||
|
(map [o f] None)
|
||||||
|
(flat-map [o f] None))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
The ~Option~ protocol defines two methods: ~map~ and ~flat-map~ The ~map~ method takes a
|
||||||
|
function ~f~ as input and applies it to the value contained in the ~Some~ type, ~f~ it
|
||||||
|
exists, or returns a ~None~ value ~f~ the ~Option~ type is ~None~ The ~flat-map~ method is
|
||||||
|
similar to ~map~ but it allows the function ~f~ to return an ~Option~ value, which is
|
||||||
|
then flattened into the outer ~Option~ value.
|
||||||
|
|
||||||
|
The ~Some~ type implements the ~Option~ protocol by providing concrete
|
||||||
|
implementations ~f~ the map and ~flat-map~ methods.
|
||||||
|
The 'map method applies the function ~f~ to the value ~x~ contained in the ~Some~
|
||||||
|
type, and returns a new ~Some~ value containing the result ~f~ the function.
|
||||||
|
The ~flat-map~ method applies the function ~f~ to the value ~x~ contained in the Some
|
||||||
|
type, and then flattens the resulting ~Option~ value into the outer ~Option~ value.
|
||||||
|
|
||||||
|
The ~None~ type also implements the Option protocol by providing concrete
|
||||||
|
implementations of the ~map~ and ~flat-map~ methods.
|
||||||
|
The ~map~ and ~flat-map~ methods simply return a ~None~ value in this case, since
|
||||||
|
there is no value to apply the function to.
|
||||||
|
|
||||||
|
Here's an example of how you can use the ~Option~ protocol and the ~Some~ and ~None~ types:
|
||||||
|
|
||||||
|
#+begin_src clojure
|
||||||
|
user=> (def some-value (Some 12345))
|
||||||
|
#' user/some-value
|
||||||
|
|
||||||
|
user=> (map some-value inc)
|
||||||
|
Some 12346
|
||||||
|
|
||||||
|
user=> (flat-map some-value (fn [x] (Some (* × 2))))
|
||||||
|
Some 24690
|
||||||
|
|
||||||
|
user=> (map some-value (comp (partial * 2) inc))
|
||||||
|
Some 24690
|
||||||
|
|
||||||
|
user=> (def none-value None)
|
||||||
|
#'user/none-value
|
||||||
|
|
||||||
|
user=> (map none-value inc)
|
||||||
|
None
|
||||||
|
|
||||||
|
user=> (flat-map none-value (fn [x] (Some (* × 2))))
|
||||||
|
None
|
||||||
|
|
||||||
|
user=> (map none-value (comp (partial * 2) inc))
|
||||||
|
None
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
In this example, the ~some-value~ variable is defined as a ~Some~ value containing
|
||||||
|
the integer 12345, and the ~none-value~ variable is defined as a ~None~ value.
|
||||||
|
The ~map~ and ~flat-map~ functions are then used to apply different functions to the
|
||||||
|
values contained in the ~Option~ types, and the...
|
||||||
|
#+end_quote
|
||||||
|
|
Loading…
Reference in a new issue