diff --git a/src/css/y.css b/src/css/y.css index 55ddd19..e25d353 100644 --- a/src/css/y.css +++ b/src/css/y.css @@ -75,7 +75,7 @@ figure img { width: 100%; } img { max-width: 100%; border: solid; } 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;} sup, sub { vertical-align: baseline; diff --git a/src/posts/0023-my-first-chatgpt-exchange/index.org b/src/posts/0023-my-first-chatgpt-exchange/index.org new file mode 100644 index 0000000..634b5b8 --- /dev/null +++ b/src/posts/0023-my-first-chatgpt-exchange/index.org @@ -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:me@@ + +* 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 +