Philipp Hagenlocher
Philipp Hagenlocher
  • 45
  • 1 372 043
Learn Haskell with HASKELL BOOKCAMP
Buy my book: www.manning.com/books/haskell-bookcamp
Get 40% off using my discount code: mlhagenlocher (valid through 18th of August 2022)
Haskell Bookcamp builds your skills with production-quality Haskell code by creating interesting projects. As you work through each application, you’ll master Haskell basics and functional programming and dip into the language’s advanced features. Haskell’s abstract concepts can be confusing-so you’ll learn them from the ground-up with real-world examples rather than tedious academic exercises. Learn how to structure real-world applications, how to work with the Haskell tool chain effectively, and what to look out for when writing critical sections in the program's logic. Best of all, each project in this book is fully extensible and customizable so you can keep tinkering with your favorites!
มุมมอง: 5 280

วีดีโอ

Haskell for Imperative Programmers #43 - Cabal
มุมมอง 10K3 ปีที่แล้ว
This video is supported by translatebox.io Cabal: www.haskell.org/cabal/ Install instructions (Windows): hub.zhox.com/posts/introducing-haskell-dev/ Editor shown in this video: vscodium.com Further reading: dev.stephendiehl.com/hask/#cabal cabal.readthedocs.io/ Timestamps: 00:00 - Intro 00:50 - Installation & First Steps 02:07 - Project Setup 07:05 - Adding Library Modules 10:40 - Building a Li...
Haskell for Imperative Programmers #42 - QuickSpec
มุมมอง 3K3 ปีที่แล้ว
This video is supported by translatebox.io QuickSpec: hackage.haskell.org/package/quickspec Code shown in the video: github.com/phagenlocher/quickspec-examples Examples: github.com/nick8325/quickspec/tree/master/examples Timestamps: 00:00 - Intro 04:25 - Simple Laws for the Addition 05:58 - concatMap Laws, Polymorphic Signatures 09:51 - Laws on our own Code 11:36 - Predicates 16:26 - Laws on fo...
Haskell for Imperative Programmers #41 - Formal Verification (using Isabelle)
มุมมอง 6K3 ปีที่แล้ว
This video is supported by translatebox.io Isabelle: isabelle.in.tum.de The Archive of Formal Proofs: www.isa-afp.org Timestamps: 00:00:00 - Intro 00:03:25 - First Steps in Isabelle 00:14:10 - Simple Induction Proof 00:21:15 - Computation Induction 00:28:00 - A failed Induction 00:35:55 - Accumulator Generalization 00:54:10 - Termination Proof 01:04:06 - Proofs on the Sortedness of Trees 01:17:...
Haskell for Imperative Programmers #40 - Termination Proofs
มุมมอง 3.2K3 ปีที่แล้ว
This video is supported by translatebox.io Further reading: www.springer.com/de/book/9783658263010 en.wikipedia.org/wiki/Termination_analysis en.wikipedia.org/wiki/Total_functional_programming Timestamps: 00:00 - Intro 01:06 - Non-Termination and Undefinedness 03:07 - What is Termination? 05:54 - Definition for Termination Proofs 07:09 - Factorial Proof 10:04 - Second Proof 12:36 - Precondition...
Haskell for Imperative Programmers #39 - Induction Proofs
มุมมอง 7K3 ปีที่แล้ว
This video is supported by translatebox.io Further reading: en.wikipedia.org/wiki/Well-founded_relation en.wikipedia.org/wiki/Ascending_chain_condition en.wikipedia.org/wiki/Structural_induction Timestamps: 00:00 - Intro 02:18 - The Induction 02:54 - Noetherian Induction 03:55 - Structural Induction 05:36 - Example of structural induction 07:12 - Problems with our proof 08:09 - Computation Indu...
Lazy Evaluation in Python
มุมมอง 5K3 ปีที่แล้ว
Python Code: gist.github.com/phagenlocher/8532fe65a5bc99cb5f835441c950baf6 Java Code: gist.github.com/phagenlocher/5c8b03d6174ea77cfa4cee4b6bc633d3 Timestamps: 00:00 - What is Lazy Evaluation? 01:42 - Functions and Thunks 03:29 - The Lazy Class 08:27 - Factorials Done Lazily 09:29 - A List of Lazy 10:12 - Infinite Lists 11:59 - A Whole Lotta Generators 15:00 - Some Considerations Support me on ...
Haskell for Imperative Programmers #38 - Monad Transformers
มุมมอง 16K3 ปีที่แล้ว
Autobots, roll out! More reading: wiki.haskell.org/All_About_Monads#Monad_transformers en.wikibooks.org/wiki/Haskell/Monad_transformers Timestamps: 00:00 - Combining IO and Maybe 02:17 - Maybe Transformer 05:12 - State Transformer 08:44 - More Transformers 09:19 - Transformers are experimental! Support me on Ko-fi: ko-fi.com/phagenlocher
Haskell for Imperative Programmers #37 - Arrows
มุมมอง 11K3 ปีที่แล้ว
Let's head in the right direction! Programming with Arrows by John Hughes: www.cse.chalmers.se/~rjmh/afp-arrows.pdf Generalising monads to arrows by John Hughes: www.sciencedirect.com/science/article/pii/S0167642399000234 Easier reading: en.wikibooks.org/wiki/Haskell/Understanding_arrows www.haskell.org/arrows/index.html Timestamps: 00:00 - What are Arrows? 00:58 - Arrow Typeclass 03:05 - Categ...
Haskell for Imperative Programmers #36 - Category Theory (Functors, Applicatives, Monads)
มุมมอง 24K3 ปีที่แล้ว
In this video we are going to get theoretical! Programming with categories: th-cam.com/play/PLhgq-BqyZ7i7MTGhUROZy3BOICnVixETS.html Category theory for programmers by Bartosz Milewski: github.com/hmemcpy/milewski-ctfp-pdf Seven Sketches in Compositionality by Brendan Fong & David I. Spivak: arxiv.org/pdf/1803.05316.pdf Applicative programming with effect by Conor McBride & Ross Paterson: www.st...
Haskell for Imperative Programmers #35 - Semigroup & Monoid
มุมมอง 13K3 ปีที่แล้ว
In this video it's going to get theoretical! Documentation: hackage.haskell.org/package/base-4.14.0.0/docs/Data-Semigroup.html hackage.haskell.org/package/base-4.14.0.0/docs/Data-Monoid.html Further reading: en.wikipedia.org/wiki/Algebraic_structure Timestamps: 00:00 - Intro 01:04 - Algebras and their definition 05:10 - Magma definition 05:35 - Semigroup definition 07:18 - Semigroup examples 09...
Haskell for Imperative Programmers #34 - Profiling
มุมมอง 4.1K4 ปีที่แล้ว
In this video we stare into the abyss until it stares back into us. ThreadScope: github.com/haskell/ThreadScope/releases Documentation: downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html Timestamps: 00:00 - Intro 01:41 - Measuring Execution Time 08:17 - Cost Centre Stack 13:03 - Measuring Heap Allocation 16:37 - Profiling the Garbage Collector 21:01 - Code Coverage 25:40 - P...
Haskell for Imperative Programmers #33 - Parallelism
มุมมอง 7K4 ปีที่แล้ว
Considering the length of this video watching at 2x speed is recommended! ;) ThreadScope: github.com/haskell/ThreadScope/releases Documentation: hackage.haskell.org/package/parallel-3.2.2.0/docs/Control-Parallel-Strategies.html Further reading: wiki.haskell.org/ThreadScope wiki.haskell.org/ThreadScope_Tour Timestamps: 00:00 - Theory on Parralelism 03:47 - Eval Monad and Strategies 09:37 - Spark...
Haskell for Imperative Programmers #32 - DeepSeq
มุมมอง 4.1K4 ปีที่แล้ว
In this video we are going to evaluate to normal form. Documentation: downloads.haskell.org/~ghc/7.10.1/docs/html/libraries/Control-DeepSeq.html Timestamps: 00:00 - Intro 00:51 - Documentation 04:22 - Basic Example 08:36 - Peano Example 11:34 - Tree Example 16:20 - Usage with IO Actions 20:35 - Discussion on Usage Support me on Ko-fi: ko-fi.com/phagenlocher
Haskell for Imperative Programmers #31 - Weak Head Normal Form
มุมมอง 7K4 ปีที่แล้ว
In this video we are going to discuss the weak head normal form. Interesting reading: en.wikipedia.org/wiki/Graph_reduction en.wikibooks.org/wiki/Haskell/Graph_reduction en.wikipedia.org/wiki/Lambda_calculus_definition Timestamps: 00:00 - Reductions 03:44 - Sharing 05:10 - Graph Reduction 05:58 - Normal Form 07:46 - Weak Head Normal Form 13:43 - Demonstration Support me on Ko-fi: ko-fi.com/phag...
Haskell for Imperative Programmers #30 - Software Transactional Memory (STM)
มุมมอง 9K4 ปีที่แล้ว
Haskell for Imperative Programmers #30 - Software Transactional Memory (STM)
Haskell for Imperative Programmers #29 - Semaphores (QSem, QSemN)
มุมมอง 6K4 ปีที่แล้ว
Haskell for Imperative Programmers #29 - Semaphores (QSem, QSemN)
Haskell for Imperative Programmers #28 - Concurrency & Threads
มุมมอง 14K4 ปีที่แล้ว
Haskell for Imperative Programmers #28 - Concurrency & Threads
Haskell for Imperative Programmers #27 - Exceptions
มุมมอง 7K4 ปีที่แล้ว
Haskell for Imperative Programmers #27 - Exceptions
Haskell for Imperative Programmers #26 - Strictness, Thunks & seq
มุมมอง 8K4 ปีที่แล้ว
Haskell for Imperative Programmers #26 - Strictness, Thunks & seq
Haskell for Imperative Programmers #25 - Compiling Binaries
มุมมอง 6K4 ปีที่แล้ว
Haskell for Imperative Programmers #25 - Compiling Binaries
Haskell for Imperative Programmers #24 - Environment
มุมมอง 8K4 ปีที่แล้ว
Haskell for Imperative Programmers #24 - Environment
Haskell for Imperative Programmers #23 - Modules
มุมมอง 10K4 ปีที่แล้ว
Haskell for Imperative Programmers #23 - Modules
Haskell for Imperative Programmers #22 - Either
มุมมอง 11K4 ปีที่แล้ว
Haskell for Imperative Programmers #22 - Either
Haskell for Imperative Programmers #21 - data, type & newtype
มุมมอง 17K4 ปีที่แล้ว
Haskell for Imperative Programmers #21 - data, type & newtype
Haskell for Imperative Programmers #20 - Advanced Exercises
มุมมอง 14K4 ปีที่แล้ว
Haskell for Imperative Programmers #20 - Advanced Exercises
Haskell for Imperative Programmers #19 - Infinite Lists
มุมมอง 12K4 ปีที่แล้ว
Haskell for Imperative Programmers #19 - Infinite Lists
Haskell for Imperative Programmers #18 - QuickCheck
มุมมอง 22K4 ปีที่แล้ว
Haskell for Imperative Programmers #18 - QuickCheck
Haskell for Imperative Programmers #17 - Monads
มุมมอง 60K4 ปีที่แล้ว
Haskell for Imperative Programmers #17 - Monads
Haskell for Imperative Programmers #16 - Type inference
มุมมอง 24K4 ปีที่แล้ว
Haskell for Imperative Programmers #16 - Type inference

ความคิดเห็น

  • @HyperSimplex
    @HyperSimplex 3 วันที่ผ่านมา

    great videos!

  • @nincako
    @nincako 4 วันที่ผ่านมา

    this video is NOT about application. The codes given are just definitions and it is heavily based on describing something very abstract. Please do not waste your time.

  • @mouduge
    @mouduge 5 วันที่ผ่านมา

    Awesome tutorial! However, I'm really not sold on Haskell's error management, it feels like a bad compromise between "errors as data" and "errors as special control flow". I think exceptions are a really bad idea, they go against the spirit of functional programming, they're easy to mishandle, they complexify many situations, they kill kittens, and the world would be better off without them. Your justification for them at 9:55 is that "if the whole runtime is failing, then only exceptions get through". But why? Why couldn't errors be returned as data? Rust manages it, it's definitely possible. IMHO, the main downsides of "errors as data" are: 1) If function f1 calls function f2 which calls function f3, and so on up to function f100, which returns an error that needs to bubble back up to f1, then all the intermediate functions f2 to f99 have a bit of work to do, which exceptions can avoid. But some synctactic sugar can make this as easy as a single character, for example Rust has the ? operator: when f99 calls f100(...)?, if the return value of f100(...) is an error, then f99 immediately returns this error. There's also map_err in case you need to tweak the error before returning it. This makes the pass-through very lightweight, and I actually like the fact that it's explicit. Exceptions can go through unnoticed, which leads to programming errors. 2) If a function h calls multiple functions g1, g2, g3, ..., g100, which may return errors E1, E2, ..., E100 respectively, and if we suppose that function h just wants to let these errors bubble up to the caller, then its error return type will be E1 | E2 | E3 | ... | E100. In Haskell you will have to define a custom data type just for function h, for example `data ErrorH = ErrorH1 E1 | ErrorH2 E2 | ... | ErrorH100 E100`. If another function G may return errrors E2 | E3 | ... | E101, then it will need its own type ErrorG, which will be treated as completely different from ErrorH by the compiler. Sadly, Haskell does not seem to support such "structural sum types" (e.g., as opposed to languages like Typescript, Flow, Elm, ROC, or Julia, which let you use E1 | E2 | E3 as a perfectly valid type). Please correct me if Haskell does have structural sum types, that would be great! Without structural sum types, you have to deal with every possible combination of errors with its own new type. I can see why exceptions are tempting in this context. Note that Rust doesn't support structural sum types either, and therefore you have to use hacky external libraries to work around these difficulties. And this limitation encourages people to bundle all related errors into a single type, like IOError, you lose a lot of granularity. In short, I don't like Rust's error system either. I haven't played with ROC yet, but its error management looks fabulous. There are no exceptions, it's just errors-as-data, with nice synctactic sugar to make passthrough pretty lightweight (+ explicit + flexible), and with structural sum types that are automatically inferred by the compiler, and let you be as granular as you want with your errors, without any typing nightmare, and proper exhaustivity checks to ensure every error is dealt with. Check out this great talk for more details: th-cam.com/video/7SidSvJcPd0/w-d-xo.html Perhaps Haskell could evolve in that direction too?

  • @mouduge
    @mouduge 6 วันที่ผ่านมา

    Excellent series, thanks so much! Regarding your warning about `seq` at 8:49, I'm not sure exactly *what the risks are* and *what to do* about them? ➤ Risks → If I understand correctly, using `seq` might sometimes degrade performance (speed or RAM usage) because it messes with the compiler's assumptions. That's the only risk, right? Or is there also a risk of compilation or runtime errors? ➤ What to do → Should I use lazy code by default, and if I hit performance issues, first try to turn the compilation optimisations on (which may automatically make things stricter when needed), and if that's not enough, then try using strict code and see if that improves things?

  • @mouduge
    @mouduge 7 วันที่ผ่านมา

    Great series, thanks! 👍 A note for Linux newbies: at 10:20, when you type `USER="Haskell user"`, you are assuming that the `USER` environment variable has already been exported. This only works because this is a pretty standard variable that is usually exported in your system's init scripts. But if you were to use a different variable name, like `GREET_USER`, then you would have to type `export GREET_USER="Haskell user"`, or else the variable would only be visible to the current shell, not to subprocesses like `greet`. This is why you had to type `export USER` at 10:32, after the variable was `unset`. Once a variable is exported, you can change its value without exporting it again, and the updated value will be available to subprocesses. Alternatively, you could set the variable only for the subprocess like this: GREET_USER="Haskell user" ./greet Hope this helps someone.

  • @carlorosso2413
    @carlorosso2413 9 วันที่ผ่านมา

    In the third exercise I understood why you say that Haskell is pure: lagrange :: [(Float, Float)] -> Float -> Float lagrange xs x = sum [y_i * lagrangeBasis xs x_i x | (x_i, y_i) <- xs] where lagrangeBasis xs x_i x = product [lagrangeOne x_i x_j x | (x_j, _) <- xs, x_j /= x_i] lagrangeOne x_i x_j x = (x - x_j) / (x_i - x_j)

  • @Mr.Beandip-ve9iz
    @Mr.Beandip-ve9iz 21 วันที่ผ่านมา

    This is great. It's the first course I've found that actually compares Haskell to what I already know. Programmers everywhere thank you.

  • @en8042
    @en8042 24 วันที่ผ่านมา

    I came up with this solution, I hope it's correct I haven't yet found an input for which it isn't. hasPath :: [(Int, Int)] -> Int -> Int -> Bool hasPath [] x y = False hasPath (x:xs) u v | (fst x == u) && (snd x == v) = True | (fst x /= u) = hasPath xs u v | otherwise = hasPath xs u v || hasPath xs (snd x) v wrapper :: [(Int, Int)] -> Int -> Int -> Bool wrapper xs u v = hasPath (xs ++ xs) u v If there are no edges, then there are no routes. If there is at least one edge and its first vertex is the start node and its second vertex is the end node, we're done. If the first vertex isn't the start node, we just skip this edge and try to find the path in the rest of the edges. Otherwise we start a search in the rest of the edges with both the first and second vertex. We also need a wrapper function which just calls into hasPath, except it doubles the edge list, since it might be possible that ignored edges in the beginning might be needed later, in other words we make sure we visit all pairs of edges in both order. Correction: doubling the list is not enough, I think we need to multiply the list by the number of its elements (number of edges).

  • @Doodoofart725
    @Doodoofart725 25 วันที่ผ่านมา

    I wonder where all the discarded thunks end up 😢

  • @exbibyte
    @exbibyte 29 วันที่ผ่านมา

    🔥thank you for the videos

  • @Russoski234
    @Russoski234 หลายเดือนก่อน

    My solution seems to work, although it's simpler. For directed graphs, the tuple (a,b) indicates the directed edge from a to b. With this in mind, if I can find a road in which I can start from a tuple with a as a source and go to another tuple while updating my source, it is just a matter of time until i find the case in which the tuple (updated_src, dst) is exactly a member of the list. It works with the list of tuples [(1,2),(2,3),(3,2),(3,4)] and returns True if i search for 1 4 and 1 3, but i don't know if it's bulletproof. Thanks for the videos! hasPath::[(Int,Int)] -> Int -> Int -> Bool hasPath [] _ _ = False hasPath (x:xs) src dst | fst x == src && snd x == dst = True | fst x == src && (fst x <= snd x) = hasPath xs (snd x) dst | fst x == src && (fst x >= snd x) = hasPath xs (fst x) dst | otherwise = hasPath xs src dst

  • @theantonlulz
    @theantonlulz หลายเดือนก่อน

    Exercise 2 is the prefect argument against functional programming.

    • @TheTIM333
      @TheTIM333 15 วันที่ผ่านมา

      prefixes = [take m n | m <- [1..length n]] Nice, simple, elegant.

  • @theantonlulz
    @theantonlulz หลายเดือนก่อน

    This video ain't it. I understood virtually nothing about data types or their uses.

  • @Nil44419
    @Nil44419 หลายเดือนก่อน

    Hi, Now I checked this in ghci. let x = 1 + 1; let y = x + 5, after forcing y to be evaluated by typing y in ghci, :sprint y is still _. Edited: I didn't mentioned the type as Int. Now its working as expected.

  • @agaveboy
    @agaveboy หลายเดือนก่อน

    hint for understanding the 2D map: the map function itself is passed as an argument to the second map function - we are applying the map function to each element (list) of the 2D list.

  • @milosmrdovic7233
    @milosmrdovic7233 หลายเดือนก่อน

    Answer #4 is needlessly complex and assumes there's always a path from x to x. I'd use something like this instead: hasPath :: [(Int, Int)] -> Int -> Int -> Bool hasPath [] _ _ = False hasPath [(a, b)] x y = a == x && b == y hasPath (a:xs) x y | x == fst a = hasPath xs (snd a) y | otherwise = hasPath xs x y

  • @MatthewHaydenRE
    @MatthewHaydenRE หลายเดือนก่อน

    Great video series. Was there a conscious choice not to use function composition?

  • @idkwhattonamethisshti
    @idkwhattonamethisshti หลายเดือนก่อน

    Yeah, I give up. This is not understandable at all

  • @densidad13
    @densidad13 หลายเดือนก่อน

    I've seen many videos in this series so far and have to congratulate you for the clear explanation style. I've heard about the STM paper before and think I'm now in a position to try to uderstand it. I'll like the refereces to the conceptual sources! Thank you.

  • @Bulbasauros
    @Bulbasauros หลายเดือนก่อน

    Ex2 doesn't remove duplicates.

  • @cordestandoff2358
    @cordestandoff2358 2 หลายเดือนก่อน

    My solution of 4 ex: hasPath :: [(Int, Int)] -> Int -> Int -> Bool hasPath array from to | null [x | x <- array, fst x == from] = False | ([x | x <- array, fst x == from] !! 0) == (from, to) = True | otherwise = ( do let from_array = [x | x <- array, fst x == from] let not_from_array = [x | x <- array, not (fst x == from)] let only_snds_from_array = [(snd x) | x <- from_array] let next_depth = [True | x <- only_snds_from_array, hasPath not_from_array x to] if (not (null next_depth)) then True else False ) main :: IO () main = do print (hasPath [(1, 2), (2, 3), (3, 2), (4, 3), (4, 5)] 1 3) So i just loop in checking of all branches, idk about speed of this sh*t, but hey! Im 15 y. o, and i just russian school boy

  • @becbelk
    @becbelk 2 หลายเดือนก่อน

    very hard... lol....forgot recursion since 1997... need recycle my brain

  • @davidrichards1302
    @davidrichards1302 2 หลายเดือนก่อน

    I always thought it was 'facility', not 'faculty'. Good thing I watched this video!

  • @ihategoogle2939
    @ihategoogle2939 2 หลายเดือนก่อน

    For doing question 3 with just the stuff discussed, I figured this would work isAsc :: [Int] -> Bool isAsc (x:xs) | null xs = True | x < head xs = isAsc xs | otherwise = False

  • @ale-hl8pg
    @ale-hl8pg 2 หลายเดือนก่อน

    Thought I'd add my 2 cents here - higher order functions seem to make this counter-intuitive (at least with was super counter intuitive to me) This was completely counter intuitive to me because I thought map . map would result in a function which takes in a list, uses the second map on the list to produce a new one, then uses the first map on the new list to produce an even newer one This isn't the case because map is a higher order function, so with how it gets evaluated, you end up with a map that internally uses a map All the other comments explain that relatively well but imo it'd be hard to call this "analogous" to mathematical composition, it's a lot more general because higher order functions complicate things a lot - as seen with this example You're not saying that you're applying one map on a list then another map on the result of that list, you're saying that you're creating a new function that is a map, which ITSELF uses a map This is a composition of maps which maps a list of a's to a list of b's, then to a list of c's: mapTransitive:: (b -> c) -> (a -> b) -> a -> c mapTransitive f1 f2 = map f1 . map f2 This is a composition of maps which uses a map to map sublists to new lists so that you get a new list: map2D: (b -> c) -> (a -> b) -> a map2D = map . map The biggest difference is the way arguments get applied - that's what changes the outcome, the order matters a lot

  • @alessiodellicolli1593
    @alessiodellicolli1593 2 หลายเดือนก่อน

    could this implementation of exercise 4 be good? Because it looks much simpler hasPath :: [(Int, Int)] -> Int -> Int -> Bool hasPath [] y z = y==z hasPath ((x1, x2):xs) y z = y==z || (hasPath xs y x1 && hasPath xs x2 z) || hasPath xs y z

  • @hotdog9259
    @hotdog9259 3 หลายเดือนก่อน

    At 10:00, you say that the tensor product is a functor, but maps objects of C. My understanding is that would be a morphism, not a functor? Or am I misunderstanding

  • @seamusmoran4776
    @seamusmoran4776 3 หลายเดือนก่อน

    Succ

  • @grego1388
    @grego1388 3 หลายเดือนก่อน

    muy bien explicado, sos crack philipp ee

  • @marcuswest4572
    @marcuswest4572 3 หลายเดือนก่อน

    Such excellent diction and delivery

  • @Lucas-ns9hd
    @Lucas-ns9hd 3 หลายเดือนก่อน

    After listening to this video without any of the visuals, I am only left with one question: What is a monad?

  • @jdchau6064
    @jdchau6064 3 หลายเดือนก่อน

    Mega gut ❤

  • @404nohandlefound
    @404nohandlefound 3 หลายเดือนก่อน

    ghci> incr 7 <interactive>:1:6: error: • No instance for (Num PeaNum) arising from the literal ‘7’ • In the first argument of ‘incr’, namely ‘7’ In the expression: incr 7 In an equation for ‘it’: it = incr 7 data PeaNum = Succ PeaNum | Zero incr:: PeaNum -> PeaNum incr = Succ I don't understand what's Wong?

    • @joshua-goldstein
      @joshua-goldstein 3 หลายเดือนก่อน

      In Haskell you can check the type of an expression using `:t <expr>`. So, e.g. if you try `:t "hello"` it will output "hello" :: String. Now try this with 7. It is a bit less clear in this case but you will see that 7 is a kind of built in num type. Now if you check the type of Zero (i.e. `:t Zero`) you should see `Zero :: PeaNum`. What you have done with the `data` keyword is define a new datatype in Haskell. Your increment function operates on values of type PeaNum, but the built-in num type.

  • @s243a
    @s243a 4 หลายเดือนก่อน

    Is there a name for the type of function algebra used to show that map2D = map . map?

  • @ujin981
    @ujin981 4 หลายเดือนก่อน

    GHCi, version 9.6.3: ghci> elem e [] = False ghci> elem e (x:xs) = (e==x) || (elem e xs) ghci> elem 2 [0,1,2] True ghci> elem 3 [0,1,2] *** Exception: <interactive>:2:1-37: Non-exhaustive patterns in function elem "elem e (x:xs) = if e==x then True else elem e xs" predictively gives the same result

    • @0LoneTech
      @0LoneTech 4 หลายเดือนก่อน

      GHCi only saw one line at a time, so you ended up with only the last equation, not the full definition. You can group lines (note how the continued prompt is ghci|): ghci> :{ ghci| elem _ [] = False ghci| elem e (x:xs) = e==x || elem e xs ghci| :}

    • @ujin981
      @ujin981 4 หลายเดือนก่อน

      @@0LoneTech Thank you! No wonder one-liner "elem e (x:xs) | length xs > 0 = (e==x) || (elem e xs) | otherwise = (e==x)" worked fine. But it felt dirty.

    • @0LoneTech
      @0LoneTech 4 หลายเดือนก่อน

      @@ujin981 That's also incomplete; it wouldn't work on an empty list. If you want to one-line it, separate the equations with a semicolon ;

    • @ujin981
      @ujin981 4 หลายเดือนก่อน

      @@0LoneTechThank you!

  • @Antagon666
    @Antagon666 4 หลายเดือนก่อน

    Is app a builtin Haskell function? Might have mentioned that at least

    • @PotassiumLover33
      @PotassiumLover33 4 หลายเดือนก่อน

      I'm guessing not since its a completely useless function lol

    • @0LoneTech
      @0LoneTech 4 หลายเดือนก่อน

      Well, yes and no. I don't think any standard function is called app, but $ and $! have the same signature and id is more general. GHC Control.Arrow also has an app function with a different signature. Once combining functions (composition) becomes routine it might surprise you how useful trivial functions are.

  • @xbz24
    @xbz24 4 หลายเดือนก่อน

    Thanks

  • @Antagon666
    @Antagon666 4 หลายเดือนก่อน

    Isn't it a huge flaw that compiler won't optimize simple recursion and you have to do tons of "magic" just to guarantee some basic speed ?

    • @andrew_ray
      @andrew_ray 17 วันที่ผ่านมา

      I believe modern GHC can sometimes detect recursive patterns that can be substituted for tail recursion and optimized that, but the happening problem makes it impossible to procedurally check if that's possible. As an aside, I'm not sure I like the explanation of this that's given here. When you call a function, memory needs to be allocated to store inputs, local constants, &c. This chunk of memory is called a stack frame. Recursion causes this to happen repeatedly and you can run out of memory easily. With tail-call optimization, you can reuse the stack frame, because all the current call is going to do is immediately return the value returned by the next call. That means we can guarantee none of the values for the current call are needed anymore.

  • @beajanos9277
    @beajanos9277 4 หลายเดือนก่อน

    Thank you so much for this content! It has helped me so much with the preparation for my Higher Programming Concepts exam at uni!! Great work!

  • @ragilo13
    @ragilo13 5 หลายเดือนก่อน

    Ex3 + 2 hours and i finally made it work. But i guess not the best way how i did it: lagrange'' :: [(Float, Float)] -> (Float -> Float) lagrange'' xs = (\k -> foldr (\(xi, yi) acc -> acc + yi * foldl (\acc (x, _) -> acc * ((k - x) / (xi - x))) 1 (filter (\(x, _) -> x /= xi) xs)) 0 xs)

  • @jumpre
    @jumpre 5 หลายเดือนก่อน

    *Spoiler to exercise #3; * --start productFold = foldr (\x y -> x*y) 1 sumFold = foldr (\x y -> x+y) 0 lbasis :: [(Float, Float)] -> Float -> Float -> Float lbasis pos xi x = productFold collection where collection = [(x-xj)/(xi-xj) | (xj, _) <- pos, xi /= xj] lfunc :: [(Float, Float)] -> Float -> Float lfunc pos x = sumFold collection where collection = [ yi * (lbasis pos xi x) | (xi, yi) <- pos] main = do print (lfunc pos 2.0) where pos = [(-2.0, -2.0), (-1.0, 4.0), (0.0, 1.0), (4.0, 8.0)] --end {- wow! this formula is done a fair bit in numerical analysis, and doing it by hand supposedly gives a number of engineeringy people big headache -- but turns out it can be expressed in ~18 lines of Haskell code which is absolutely mind-blowing to me. My python version was about 45 lines long. -}

  • @humairafasihahmed1754
    @humairafasihahmed1754 5 หลายเดือนก่อน

    don't really get how let bindings are any different from imperative formats

  • @Antagon666
    @Antagon666 5 หลายเดือนก่อน

    Bruh any solid C compiler would compute Z first.

  • @sascha-oliverprolic923
    @sascha-oliverprolic923 5 หลายเดือนก่อน

    Just watched this video for the n-th time.

  • @kebman
    @kebman 5 หลายเดือนก่อน

    This is why I failed math. I've since concluded that it was the teacher's fault, because I can full well understand and apply quite complex functions, and I now know how to program in several languages. But this? Nah. No thank you. If I can't play with it, then I guess it's not for me.

  • @guntherklausen6891
    @guntherklausen6891 5 หลายเดือนก่อน

    I liked my Implementation of the elem-Function : elem y xs = not (null [x | x <- xs, x==y]), because I like the list comprehension stuff. For nub, I have an implementation that throws out all later duplicates by remembering a list of everything it went through. that is a help function of course: nubBuild :: (Eq a) => [a] -> [a] -> [a] nubBuild [] ys = [] nubBuild (x:xs) ys | Main.elem x ys = nubBuild xs ys | otherwise = x:(nubBuild xs (x:ys)) so the actual nub is just nub xs = nubBuild xs [] I would love to know a better way to throw out later duplicates, but I have no Ideas. My isAsc is essentially the same thing, but I use list comprehension to check if the remaining list has smaller elements, so quite wastefull it would seem to me. I know I am 4 years late, but hey maybe someone someday will read this

  • @samuraijosh1595
    @samuraijosh1595 5 หลายเดือนก่อน

    Woah this is AMAZING. Haskell's build tooling has always been a headache for me since i started learning it 1 year ago. Your video is a game changer. I hope this blows up on the algorithm some day.

  • @martandrmc
    @martandrmc 5 หลายเดือนก่อน

    Coming back to this series again and again whenever I regain the mood to practice Haskell I always try the exercises again, specifically the fourth one which I consider a right of passage. I am happy to announce that I not only finally managed to solve it, but I did so writing on my phone at 3 AM! Thank you so much for this amazing series. If it wasn't for it I wouldn't be into functional programming right now!

  • @Sakuraigi
    @Sakuraigi 5 หลายเดือนก่อน

    Can you write real programs in this language like procedural or what lol?

  • @bocchitherock-ob2bl
    @bocchitherock-ob2bl 6 หลายเดือนก่อน

    idk why no one seems to share the opinion that the Integer -> Integer -> Integer -> Bool thing looks very ugly. idk why the creator(s) thought it was actually a good way to represent what seems to be the equivalents of parameter type AND return type with this syntax. the more i look at it, the less sense it makes. but anyway, syntax aside, haskell is a language i am intrigued in and find interesting.