Cristian Urlea

Cristian Urlea

I am a Research Associate at the University of Glasgow and have an interest in parallel programming, compilers, functional languages and of course Haskell.

Location Glasgow

Activity

  • > I have a feeling that I could combine both map/filter

    That's a good feeling to have when you're programming in Haskell!
    Most of the time, it is the right thing to do, check out Hutton's tutorial: http://www.cs.nott.ac.uk/~pszgmh/fold.pdf

    (Section 3.2 is what your hunch is pointing to )

  • Not sure what the question is. If the problem is that `abs -3` does not seem to compute, try `abs (-3)`. The issue there is that `-3` is not "the literal value of negative three" but "the negation operator `-` applied to the literal value `3`".

  • @EduardoFrança I can't give you a straight-forward answer as I'm not familiar enough with the implementation details in the GHC compiler. GHC does not entirely reflect the theoretical understanding of the Haskell language that I peddle here in the comments section.

    > Is this is haskell's automatic Currying mechanism?

    As far as the type-system (and...

  • Sadly the answer is no for now. The web interpreter has limited functionality. We may find a more flexible solution in the future though.

    That said, it is better if you install and work with a native Haskell environment on your own machine. It may not just "magically work out of the box" however you will learn a lot more in the long run.

  • It is an expression[1]. Everything in Haskell is an expression :)

    [1] https://optimistictypes.com/if-then-else-case-expressions-and-guards-oh-my/

  • > Pushed to its extreme it kind of turns into Prolog :D

    Functional languages are indeed only one small step away from things like Prolog.

    > one just needs to express the space of the problem in one function/recursive structure/something and write a "navigator" to browse that structure

    Often you can derive the "navigator" from the problem description...

  • @MatiasLopez Indeed, Haskell on Linux would be the way to go in terms of ease of installation/use and maintenance.

  • @MatiasLopez You can use cabal to install and manage libraries like QuickCheck. The only code you end up running is your own application that uses QuickCheck.

    You may be able to download and use the QuickCheck library without cabal but it would be more convenient to use cabal if you can. Can I perhaps ask as to what is preventing you from installing cabal...

  • [part 2]

    > can we do the same for custom type classes

    You most certainly can do that using the same Generics functionality. There is an exact description of what is needed in the "A generic deriving mechanism for Haskell" paper [2]. It comes with a related library that you can use[3]. There is also a more recent video tutorial on how you might do this...

  • [part 1]

    > How does the 'Show' typeclass define the default implementation

    The exact answer is a bit involved. One would ideally be familiar with Haskell Generics (documentation in [1]) but the long and short of it is that:

    - You can think of every Haskell data-type as being either a "primitive" type ( think integers ) or "composite" data-types that...

  • @ChristianW

    Thank you for pointing out the exact place in the tutorial that threw you off! We'll get it sorted :)

  • > I think Java is more user friendly than Python.

    There's signifiant ups and downs to each. To say that Java is verbose would be an understatement. At the same time I would rather wear out my keyboard and have some measure of static type checking on by default, so Java wins over Python in my book.

    What's more important is that *all* mainstream...

  • @ChristianW Simply use the operator form: ` 3 : [4,5] ` where `(:)` is the "cons operator" the text refers to.

    The name "cons" is simply given such that you have something to pronounce as you read source-code. Here the name evokes that you are *cons*tructing a list. Reading operators "aloud" is a good habit to get into because it makes following unfamiliar...

  • @YuhuaiWu Could you please tell me what interpreter you used? Here is what i got in GHCi:

    ```
    Prelude> x = 3
    Prelude> x
    3
    Prelude> y = x + 5
    Prelude> y
    8
    Prelude> x = 5
    Prelude> x
    5
    Prelude> y
    8
    Prelude>
    ```

    You will note that y does not change to account for the "new" x. If you were trying this in the web interpreter, please beware that...

  • > Why does " data Pair = Pair Int Double " has a Pair on the right hand side

    The `Pair` on the left ( in `data Pair`) is the **name of the data-type** we are defining. The `Pair on the right ( in `Pair Int Double`) is the **name of the data-constructor** we are defining. To make this less confusing, you may choose different names:

    ```
    data Pair =...

  • > how do we arrive to the type h being: h:: (T1->T2) -> (T2->T3) -> T1?

    We know that
    ```
    v :: T1
    ```

    This already means the output type from `h` must be `T1`
    We also know that h takes two function arguments:
    ```
    v = h f g
    ```

    So then `h :: (f_in -> f_out) -> (g_in -> g_out) -> T1`

    but we know that the first argument `f : T1-T2` so then:...

  • @AndrejNovikov

    > would pattern matching do the same optimisation?

    Yes, I would expect it to do the same optimisation (with less effort) because `take` is implemented with pattern matching [1]:

    ```
    -- It is an instance of the more general 'Data.List.genericTake',
    -- in which @n@ may be of any integral type.
    take :: Int -> [a]...

  • If concise is what you value most I suspect you'll like "Squiggol" quite a bit: https://en.wikipedia.org/wiki/Bird%E2%80%93Meertens_formalism

  • @ChristopherBare

    > but I wonder if that comes at the cost of having to make more decisions up front.

    You don't have to make *more* decisions up front. You simply have to state them. This is not an "additional burden" as you would have had to state the same assumptions ( by formulating testing units ) in a dynamic language. The only difference is that...

  • Both `/` and `*` operators have the same priority. In GHCi you can check this:

    ```
    Prelude> :info (*)
    class Num a where
    ...
    (*) :: a -> a -> a
    ...
    -- Defined in ‘GHC.Num’
    infixl 7 *

    ````

    ```
    class Num a => Fractional a where
    (/) :: a -> a -> a
    ...
    -- Defined in ‘GHC.Real’
    infixl 7 /

    ```
    Given the use of...

  • > :: defines the type of variable ?

    Yes

    ```
    f :: Int -> Int -> Int
    ```
    Means that `f` is a "variable" having the type of a function: `Int -> Int -> Int`.

  • @JulianOng Perhaps I am missing something from your argument, so I'll trace my thinking. The definition you gave:

    ```
    Tree = Empty | Node Int Tree Tree deriving Show
    ```

    Is "identical" (structurally) to that given in the article:

    ```
    data Tree = Leaf | Node Int Tree Tree deriving Show
    ```

    There is of course the naming difference between...

  • @AndrejNovikov Nothing would terminate due to laziness alone in that example because `properfactors` tries to produce *all* proper factors and does not have a "short-cut" (such as checking if the input divided by factors found == 0). Where you *might* get an optimisation like the one you suggested is if you did only demanded a finite number of outputs:...

  • The converse is also true: one advantage to using `where` is that your function does not read solely from top to bottom :). At certain times you may want to delay the presentation of extraneous details to make the overall intent of the code more clear. The following function may seem meaningless at first:

    ```
    foo :: Shape -> Float
    foo C r = ...

  • > Not very clear to me, that "case == @" means it's using "case"?

    Basically yes. In the GHC core language, things need to be stated a lot more concretely. The `@` symbol specifies that the operator on the left, `==` is to be interpreted according to its definition for the `Pet` type. In short, `@` applies a type argument to a polymorphic function,...

  • Very nice observations! I'll add a few comments for the sake of conversation:

    > So 'map' could be syntactic sugar for list comprehensions, though I would doubt that.

    Usually the more complex item desugars the simpler item. In this case the list comprehension is syntactic sugar for a number of things, including a simple map, as you well noticed.

    >...

  • @GustavoRobertiPassini
    > can we debug a Haskell program "step-by-step"

    You most certainly can but it is important to define what exactly a "step" is.

    For monadic code, such as for example input/output operations happening in an "IO do block" the actions are explicitly sequenced by the do block itself. This means that the outer-most representation of...

  • You can give `ghc` a few extra flags and it will print the core representation of the application being compiled [1]. Give it a go and see what pop up, I'd be interested in hearing the answer as well.

    [1] https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/debugging.html#core-representation-and-simplification

  • The main issue here is that `parseDiv` does not have an appropriate type-signature which is getting "default Haskell" all confused about how to proceed with type inference. Fortunately , ghci gives you a hint about what may help ( "Use Flexible Contexts to permit this"). To do this you must issue:

    ```
    :set -XFlexibleContexts
    ```
    Before the last...

  • Can you reply with one of these examples here please? That will help us find out what is happening.

  • > Inside do block it's impossible to use `where`

    Indeed. This is because evert let expression inside a do block defines a "further nested scope" in which the bindings are valid. A `where` clause would define a further set of bindings that would also have to be attached to a certain `scope` in which they are valid, but then you would have the problem of...

  • Yes `\x y -> ...` is the same as `\x -> \y -> ...` because any function of type ` a -> b -> c ` is actually a function of type ` a -> (b -> c)`.

    I went over the implications in my other comment here: https://www.futurelearn.com/courses/functional-programming-haskell/8/steps/881435/comments?page=1#comment_51285083

  • @PaulHorth One way to find functions like these, provided you can reason about the type that they should have is to use Hoogle[1]. In this case, we know that we want something to reverse function arguments. If the input function type is

    ```
    f : a -> b -> c
    ```
    The output function type should be:
    ```
    f' : b -> a -> c
    ```
    You type the function type...

  • Clarke's third law states: "Any sufficiently advanced technology is indistinguishable from magic."

  • @PaulHorth when you use the `-` operator as a function `(-) a b` the meaning is ` a - b `. Consequently `(-) 4 x` is ` 4 - x`, as you noticed.

    The most straight-forward solution is that provided by @RolfSpeer, another is to use `flip` to swap the order of the arguments:

    ```
    Prelude> map ( flip (-) 4 ) [1,2,3,4]
    [-3,-2,-1,0]
    ```

  • [Duplicate answer] It really shouldn't be. You would never name a variable with parentheses in the name. It just looks that way for the sake of the narrative. If you follow the content instructions closely, you'll see that you're only meant to use the long on-liner that follows:

    ```
    do { planet <- getLine; home <- getLine; putStrLn ("greetings " ++ planet...

  • It really shouldn't be. You would never name a variable with parentheses in the name. It just looks that way for the sake of the narrative. If you follow the content instructions closely, you'll see that you're only meant to use the long on-liner that follows:

    ```
    do { planet <- getLine; home <- getLine; putStrLn ("greetings " ++ planet ++ "ling.");...

  • > "cons" is a function

    It is actually a data constructor (which is technically also a function, so you're not wrong).

    > But, in the first equation we are applying a function backward.

    That is actually what is known as "pattern matching". Because `(:)` is a data-constructor that takes two term-level arguments: `x` the new head of the list and `y`...

  • You missed something :)

  • There should be no space between `-` and `>`, the entire arrow is to be written as a single "word" : `->`. We'll fix the type-setting issue, thank you for highlighting it!

    > Is Haskell going from right to left or from left to right ?

    To clarify, the two statements: `This is traditional mathematical notation; [..] the functions are used in right to...

  • > except PHP, which is unbeatable for graphics intensive video game programming
    ಠ_ಠ

  • That's interesting. Could you please paste the entire definition for `f` that gives that type ? In GHCi version 8.6.5 i get:

    ```
    Prelude> let f x xs = x + length xs
    Prelude> :t f
    f :: Foldable t => Int -> t a -> Int
    ```

    This is because `Foldable t` has a method `length` but is the most generic. When we use `head` as well, this tells the type...

  • The fact that both versions have the same type, which you brought into focus with this question, is quite important:
    ```
    (\x -> (\y -> (x, y))) :: a -> b -> (a, b)
    (\x y -> (x,y)) :: a -> b -> (a, b)
    ```
    The first version highlights the fact that the outer lambda function takes a single argument, `x`, and it returns the inner lambda function as its...

  • The first step is to attempt to describe what you don't understand. This description need not be perfect, or even accurate, for that matter, but it will help us find where exactly you are stuck. Please try to give a summary of what you have tried to do and how it *might* relate to the course material you've seen so far, and we'll take it from there.

    You...

  • There is too much to say on the topic oh how `abstraction` and `representation` relate to Haskell and I/O in this comment section, but I will leave a book recommendation [1] for anyone looking for some thought provoking entertainment related to these ideas.

    [1] https://en.wikipedia.org/wiki/G%C3%B6del,_Escher,_Bach

  • Haskell is really particular about code (and white-space) alignment. One way is to use appropriate spaces or tabs:

    ```
    do
    __ x <- getLine
    __ putStrLn ("hello " ++ x)
    ```
    I've had to use underscores to indicate where a space character ` ` should be, as these won't render properly in the comments here.

    Another is to place everything on the same...

  • The backslash is simply syntax used to define an `anonymous function` which is to say a "function without a name". The backslash symbol was chosen because it looks sort of like the greek symbol `lambda` , as `anonymous functions` are also known as `lambda functions` (from lambda calculus).

    ```
    ( \ x -> x + 1 ) 3
    ```
    Is simply equivalent to
    ```
    f x...

  • > it could be fun to try to take Haskell concepts and apply them to another language you know.

    I can confirm that it's not only fun, but also a good way to spot and fix bugs in legacy codebases. Once you start applying some structure borrowed from Haskell, loads of painted over cracks start to appear. In a larger sense this happening organically, all of...

  • > is f :: Int -> Int -> Int a statement or an expression?

    By itself `f :: Int -> Int -> Int` is the "type of a function" so I'll take your question to be: "Are functions/values of this type statements or expressions ?" and the answer is that they are indeed expressions.

    An expression is simply a grouping of symbols that can stand in for `variables` ,...

  • > Why is there a let 'statement' ?

    There isn't, I just end (ab)using term for a number of reasons because
    I know it communicates the concept of what it "effectively does" reasonably well. Even though the imprecise use partly due to a force of habit, i admit that it's a setup. I know that someone will eventually ask the question you just asked :) ( A...

  • > I/O is really outside Haskell

    Everything is "outside" Haskell. in that sense. In the way that the `Float` type is a loose model of fractional numbers and `Int` values are simply an "approximation" for whole numbers ( one that is perfectly accurate up to what can be represented in the word-size and perfectly inaccurate beyond that ) so is `IO` a model of...

  • It's not. The accumulator need only be "passed in" on the last function call ( top of the stack , where the input list is empty : ` go [] = z` ). In every other instance, it need only be "passed out" , meaning we can just use the return value.
    As the accumulator only gets passed in once, and its value is exactly the same as that passed in to the...

  • > This adds a dimension of reliability above and beyond testing.
    > might need an internal training program

    Arguably one would need an even greater deal of training to achieve the same reliability standard in a team that does lean on the imperative style. Then the issue boils down to optimising between: hiring cost ( money and time ), training cost (...

  • The written segments of the course tend to evolve a little more freely due to the practicalities involved. Video updates are better done in batches, so please keep that feedback coming. We are taking note of it :)

  • > Or in ... is not mandatory when using do?
    This is the closest answer, it is not to be used at all. With `do notation` the let statement syntax does not call for the `in` keyword as it is actually translated into a bind operator (>>=).

  • > must we employ explicit parenthesis structures

    The use of parentheses is simply the most direct syntactical tool to explicitate association. So strictly speaking: you need structure ( via syntax or implied rules ) but they need not be parenthesis. Another equally viable option is to use Reverse Polish notation [1], where the "fixity" negates the need...

  • > That is these two expressions do not reduce to the same thing.

    Yes, that is what i meant through the use of `r1` and `r2`. I should have explained my use of the word "intermediate" as sourced from compiler development. I meant to denote that the expression, perhaps ` a * ( b * c`, may be a part of a larger expression: ` d * ( a * (b * c)) ` and...

  • The untyped lambda calculus is Turing-Complete [1]
    You can write an untyped lambda calculus interpreter in Haskell [2]
    -> Haskell is Turing complete

    Octonions define an algebra.
    An algebra specifies computation ( values, operations on values, the order of operations)
    A Turing complete language can simulate any computation
    -> Haskell can simulate...

  • Since (String,Int) is a type, and a List is parametrised by a type, then a list of (String,Int) is also a type:

    ```
    Prelude> :kind [(String,Int)]
    [(String,Int)] :: *
    ```

    Knowing that you can simply define `Map k v` to be equal to `[(k,v)]` and that you can implement your Map operations as operations on lists, you now can see why `Map k v` needs two...

  • Something that may help further is to think of `Map String Int` less abstractly. How would you implement a data-structure that remembers mappings from Strings to Ints? One obvious implementation is to remember a list of individual mappings. If you want to keep a pair of items, one of which is a String and the other an Int, you use a tuple:

    ```
    type Map...

  • @DouglasLewit

    > but most (or all?) matrix algorithms depend upon mutable data structures!

    I disagree. All of the matrix algorithms you might be familiar with may depend on mutable data structures, but that is not to say they are, in the most general sense, the only or best algorithms to use. If you are running them using an imperative language...

  • > Why the United States military loves APL ?

    Only speculation on my part but the support for Multi-dimensional arrays and Array Algebra are what I see as valid reasons.

    Most engineering disciplines make heavy use of a the "matrix operation view" of the various theoretical concepts needed for the job. Matrices can be used easily, mechanically, and most...

  • @RogerTobie

    > Haskell suffers from some of the same problems as APL although APL is much worse.

    I suspect you have not yet had the pleasure of experiencing some of the many Haskell Language extensions that are in wide use. Haskell can be much worse. That said, my opinion is that the problem you describe is entirely down to habituation and perhaps a lack...

  • > Does that mean we are supposed to map a String to an Integer

    The type declaration:

    ```
    set :: Data.Map.Map String Integer
    ```

    Means that we are declaring `set` to have the type defined by parametrising Map with two type arguments. If we load this in GHCi:

    ```
    Prelude> import Data.Map
    Prelude Data.Map> :kind Map
    Map :: * -> * ->...

  • Coming back to your specific questions around:

    ```
    set :: Data.Map.Map String Integer
    set = Data.Map.empty
    ```

    > Does that mean we are supposed to map a String to an Integer ?

    The first bit, `Data.Map` is a qualified module name. You may think of it as a `namespace` in C land, or simply a "path" on the file-system where the source-code we are...

  • A `Generic` is really just short-hand for a `Generic Type`, meaning a type that is parametrised by another type. The most basic example is that of a `List Type`

    In most programming languages one always talks about a concrete type of list such as "a list of integers" ( Haskell: [Integer], Java: ArrayList<Integer>, C: int foo[]; ) rather than about the...

  • > Is "data" the equivalent of asserting a type definition in some other language?

    Yes it there to mark that what follows is a type definition.

    > Does this make Red, Blue, & Yellow **into types** for use in the case statement?

    No, these are not types. Red, Blue and Yellow are distinct *values* of the type Color. In the same way that 0, 1, 2, 3 are...

  • You are correct, operators are just infix functions. You can use regular functions as operators using back-ticks, for example: `foo`. Or use operators as functions by wrapping them in parenthesis, for example: (+) 3 2 -- = 5

  • You find yourself in a room, alongside a friend and a game-show host who announces:

    "I have here, in my hand, a recipes for apple pie. There is a fruit vendor downstairs, as well as a shop nearby that sells flower and sugar. The first of you to make an apple pie appear receives $10000. You also have access to a universal robot that can cook ten times...

  • I'll reproduce parts of a comment I made on a previous instance of the course:

    One possible reason why Haskell literature mostly fails to make this distinction clear is because Haskell only really has expressions and so there's not much one could say about statements, except to contrast other languages, and then the exact definition of what an ...

  • Things will be a little confusing at first because there's often a a heavy `circular dependency` aspect to programming language courses. Sorry Thomas!

    The only way around it, unfortunately, is to sometimes present a concept A "out of the blue", ignore the fact that most of it will not sink in and then make use of the 5% worth of intuition it gives you to...

  • The supposed `set_color` function does not exist unless you define it yourself. Instead you might assign an actual color to your variable, by the use of a data-constructor:

    ```
    color = Red
    ```
    Thereafter the case statement should work. I would suggest writing the entire application in a `.hs` file and loading it in GHCi. The pattern matching using the...

  • In the first instance, you're getting a parse error because the interactive Haskell interpreter expects you to use a let-statement to define `x`:

    ```
    let x = 24
    ```
    The answer to your second question is a little more involved. GHCi provides some additional syntax sugar to make interactive editing possible, and this makes look as if it's violating...

  • You are indeed correct. Interestingly there is a deeper programming language specific lesson here. As far as Haskell is concerned, that is a distinction without difference. One may name the variable holding that quantity anything at all and the program would behave the same as it will be α-equivalent....

  • Read through the last section ( `Lists are lazy` ) carefully. If you follow through the text you should have two definitions in scope ( one for `xs` and one for `xs2` ) before you get to the last code-block which will then happily run using (and replacing) these pre-existing definitions.

  • The function type declaration is not ambiguous due to the associativity of the function type operator (->). If you were to check it in ghci you would get:
    ```
    Prelude> :i (->)
    data (->) (a :: TYPE q) (b :: TYPE r) -- Defined in ‘GHC.Prim’
    infixr 0 ->
    ```
    The `infixr` keyword means that the arrow (->) is right-associative. In other words `Int -> Int...

  • @ChristopherGiles

    I'm not 100% sure but i think it's because in GHCi " 1 = 2 " is just shorthand for monadic bind inside the IO monad

    In order to bind and pattern-match, you must be able to match literals as well. Consider what happens when we swap out the IO monad for an Identity Functor:

    type Seconds = Float
    type Minutes = Integer

    secs...

  • @TomSturgeon

    '<‘ and '>' are simply the (ascii) characters.

    "char '<' " will parse a less-than character
    thereafter "identifier" will parse an entire name
    thereafter "char '>'" will parse a greater-than character.

    Because all three parsers are combined sequentially (inside the do-notation block each parser is invoked one after the other). ...

  • There's no right answer. It all depends on what is more readable, concise and appropriate to the particular instance you're implementing. Do whatever feels right, there's nothing to stop you from coming back to the decision later.

    That said, If you have loads of instances that have the same implementation for some method, you wouldn't want to duplicate the...

  • You're not meant to read "sq x y = (sq x y)" as valid Haskell code; the statement that proceeds it reads "so the following equivalence holds".

    What we mean is that invoking sq anywhere like this: "sq x y" would be exactly the same as invoking it as "(sq x) y" which when applied to 4 and 3 would be the same as first defining "sq4 = sq 4" and then calling...

  • If you're not lacking the time, it's well worth thinking about how you'd implement concepts you learn from this course in Lisp as well. It will greatly enhance learning by forcing you to try the same exercise twice, with and without the training wheels (syntactic sugar and static types respectively).

  • @JuhaPeltoniemi There is a logic, at least to the one example you've mentioned: "=". The error here is thinking of the "=" as assignment for which the symbol makes no particular sense. If you start thinking of " x = 5 " as stating that x and 5 are in fact equal ( or substitutable for one another ) it all starts looking a lot less cryptic.

    Here's a more...

  • @FritzMaeier If i had to guess, it would be down to a difference of philosophy. Lisp came about in a time when the theory hand't strayed far from simply typed lambda calculus, so you get a dynamically typed language where constructing a list is a function.

    Haskell's modus operandi is heavily reliant on static typing, and thus lists are viewed as a type,...

  • @JamesManley One thing to consider is when deciding is the manner in which you want your code to be read. If you think the reader will get a better idea of what the code does in a bottom-up fashion, you present leaf nodes of your argument first with let expressions. If you think a top-down approach is better suited, you give your reader a high-level view,...

  • @olugbengaoti If you'll permit me some advice: focus on simply using Monads by example, understanding will come with exercise quicker than it will by reading up on what a monad is. Monads are abstract beasts and such do not have meaning outside of a context, that's why it's such an impossible task to "get" or even teach about them.

    Just don't sweat it and...

  • @JürgHerzog I wouldn't go searching for meaning where there likely isn't. The point is that GHC does not like to inline recursive function definitions, so you make the functions definition non-recursive ( foo x y z = go ) and sweep the problem under the rug ( go is recursive but it's no longer top-level as it's in the where block ).

    If I had to guess, the...

  • Been trying to find an answer with some authority for weeks now, and I finally found it: https://neilmitchell.blogspot.com/2019/04/foldr-under-hood.html

    The longer answer is linked from that article: https://www.microsoft.com/en-us/research/wp-content/uploads/2002/07/inline.pdf

  • @BenjaminWeaver

    I suspect Tom is hinting at Lips style closures. There's a nice discussion on the subject here: https://letoverlambda.com/textmode.cl/guest/chap2.html

  • There's nothing preventing you from generating a truth table like [True,False] with list comprehensions and then say mapping not over it to obtain [False, True].

    Similarly you can generate sub-parts of your table with multiple comprehensions and then combine them together to incrementally generate your data.

    Unless i'm missing something ?

  • LYAH warns about this behaviour early on: http://learnyouahaskell.com/starting-out#texas-ranges

  • That would be a reasonable thing to say, yes. Both "f x = x + 1" and " fl = \x -> x + 1 " get compiled down to the same GHC core language anyway so the distinction is moot, but it's fair to say that a named function is no longer anonymous.

    Even though this is a distinction without a difference, it's a good question to ask as it reveals details about how...

  • You should see the greek letter lambda "λ" on the left side of the page. If you click next to it, that is where you are supposed to enter your Haskell code.

    There are instructions on the right, with the key Haskell bits highlighted in red.

    The first thing you enter is "next", to receive the first instruction, which will be to enter "not True" next to...

  • @ScottPendlebury

    It doesn't. What looks like reassignments in GHCi are actually nested let-expressions inside a do-notation IO block. This is because you want GHCi to look more "interactive", when it's supposed to be pure. Thus the following GHCi syntax:

    x = 1
    x = 3
    x

    Would look like this in a Haskell source file:

    main :: IO ()
    main = do...

  • @UniversalSimplexity

    I called it a let-statement due to force of habit, it's actually a "let expression".

    The long-winded answer is that Haskell does have statements, only that all statements in Haskell are actually expressions and thus there is no way to discriminate amongst the two. And as the important thing is that expressions evaluate to yield...

  • You can type in "forget <variableName>" before you re-assign and that will get you going.

    As for the reasoning: There's a bit of a mix of factors:

    1. The Haskell code runs on the server
    - because running Haskell in Javascript would be a bit much.

    2. Web-apps should not track user-state as a general rule (enables caching, clients can disappear at...

  • I will stop with the explanation here for now, but not because "it's already been explained later in the course", but because all of this will only truly make sense when you "discover" monads for yourself.

    We're now operating with abstract notions which don't have a "generic meaning". They do have meaning when used to solve concrete problems though....

  • Part II:

    In the case of expr4, though, you haven't used the "<-" notation, and neither have you explicitly bound ("injected") the line we read in with getLine , into the putStrLn I/O action.

    The reason you need to explicitly do that is because ordering matters. You can not print a string you've read from the user, before you read it from the user...

  • @MarcToma

    There's quite a bit that we haven't explained yet which is why the sequence of I/O actions seem to behave so strangely.

    The first part of the explanation has to do with the "do notation", as used in expr3 and your attempt at expr4:

    expr = do {
    <do notation code here>
    }

    putStrLn and getLine , when used in certain ways inside a do...

  • @MarcToma
    You don't need any explicit annotations. Can you provide any details into how you are running this, and what errors you get ?

    "minmax = \x y -> [min x y, max x y]" should just work, as is, in the ghci repl.

  • The definition of a function (for example f x = x + 1) _is_ evaluated (lazily or not, the distinction does not matter yet). The value that it yields is *the function f*. You can then use that value, that is a function, to build up another expression, such as "f 3". In this latter example the value of the function f was applied to the literal 3, and as function...