├── .gitignore ├── CharlaOSL.pdf ├── Haskell Literario ├── LICENSE ├── bintree.lhs ├── fibonacci.lhs ├── hask-std.lhs ├── hask.lhs ├── makefile ├── monoides.lhs └── quicksort.lhs ├── LICENSE ├── PrimeraParte ├── 1-intro.hs ├── 2-tipos.hs ├── 3-variablesTipo.hs ├── 4-patrones.hs ├── 5-curry.hs ├── 5-curry.py ├── 6-listas.hs ├── 7-ordenSup.hs ├── 7.2-foldr.hs ├── 8-tipos.hs ├── 9-clases.hs ├── 9.2-clases.hs ├── PrimeraParte.ipynb └── wcount │ ├── mimi.hs │ ├── sort.hs │ ├── wcount.cc │ ├── wcount.hs │ └── wcount.py ├── README.md ├── SegundaParte ├── 1.funtores.hs ├── 2.errores.hs ├── 3.distribuciones.hs └── 4.parsers.hs ├── apuntes ├── introHaskell.pdf ├── introHaskell.tex └── sections │ ├── apendice.tex │ ├── constr.tex │ ├── defTipos.tex │ ├── funciones.tex │ ├── ghc.tex │ ├── listas.tex │ └── tipos.tex └── ejercicios.md /.gitignore: -------------------------------------------------------------------------------- 1 | PrimeraParte/wcount/examples/* 2 | ## Literate haskell auxiliary files: 3 | *.hi 4 | *.o 5 | !examples/*.lhs 6 | examples/* 7 | 8 | ## Core latex/pdflatex auxiliary files: 9 | *.aux 10 | *.lof 11 | *.log 12 | *.lot 13 | *.fls 14 | *.out 15 | *.toc 16 | *.backup 17 | examples/*.pdf 18 | 19 | ## Intermediate documents: 20 | *.dvi 21 | *-converted-to.* 22 | # these rules might exclude image files for figures etc. 23 | # *.ps 24 | # *.eps 25 | # *.pdf 26 | 27 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 28 | *.bbl 29 | *.bcf 30 | *.blg 31 | *-blx.aux 32 | *-blx.bib 33 | *.brf 34 | *.run.xml 35 | 36 | ## Build tool auxiliary files: 37 | *.fdb_latexmk 38 | *.synctex.gz 39 | *.synctex.gz(busy) 40 | *.pdfsync 41 | 42 | ## Auxiliary and intermediate files from other packages: 43 | 44 | # algorithms 45 | *.alg 46 | *.loa 47 | 48 | # amsthm 49 | *.thm 50 | 51 | # beamer 52 | *.nav 53 | *.snm 54 | *.vrb 55 | 56 | #(e)ledmac/(e)ledpar 57 | *.end 58 | *.[1-9] 59 | *.[1-9][0-9] 60 | *.[1-9][0-9][0-9] 61 | *.[1-9]R 62 | *.[1-9][0-9]R 63 | *.[1-9][0-9][0-9]R 64 | *.eledsec[1-9] 65 | *.eledsec[1-9]R 66 | *.eledsec[1-9][0-9] 67 | *.eledsec[1-9][0-9]R 68 | *.eledsec[1-9][0-9][0-9] 69 | *.eledsec[1-9][0-9][0-9]R 70 | 71 | # glossaries 72 | *.acn 73 | *.acr 74 | *.glg 75 | *.glo 76 | *.gls 77 | 78 | # hyperref 79 | *.brf 80 | 81 | # listings 82 | *.lol 83 | 84 | # makeidx 85 | *.idx 86 | *.ilg 87 | *.ind 88 | *.ist 89 | 90 | # minitoc 91 | *.maf 92 | *.mtc 93 | *.mtc0 94 | 95 | # minted 96 | *.pyg 97 | 98 | # morewrites 99 | *.mw 100 | 101 | # nomencl 102 | *.nlo 103 | 104 | # sagetex 105 | *.sagetex.sage 106 | *.sagetex.py 107 | *.sagetex.scmd 108 | 109 | # sympy 110 | *.sout 111 | *.sympy 112 | sympy-plots-for-*.tex/ 113 | 114 | # todonotes 115 | *.tdo 116 | 117 | # xindy 118 | *.xdy 119 | -------------------------------------------------------------------------------- /CharlaOSL.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libreim/haskell/ebe17a649bd50ee69340f2de803086fe32cd6f5d/CharlaOSL.pdf -------------------------------------------------------------------------------- /Haskell Literario/LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /Haskell Literario/bintree.lhs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Árboles binarios 3 | author: Pablo Baeyens, Mario Román 4 | --- 5 | 6 | Definición 7 | ---------------- 8 | 9 | Los árboles binarios se definen muy fácilmente por recursividad. Por un lado 10 | tenemos el árbol vacío, que es el caso base, y por otro tenemos que un árbol 11 | consiste en un nodo del que surgen dos árboles binarios a su vez, un **subárbol 12 | izquierdo** y un **subárbol derecho**. 13 | 14 | \begin{code} 15 | data Tree a = Empty 16 | | Node a (Tree a) (Tree a) 17 | deriving Show 18 | \end{code} 19 | 20 | Lo hacemos polimórfico dependiendo de la variable de tipo `a`. 21 | 22 | 23 | Funciones básicas 24 | ------------------ 25 | 26 | Con estos árboles, las funciones como los órdenes o la altura se escriben por 27 | recursividad. Por ejemplo, la *altura* de un árbol es uno más de la altura de su 28 | mayor subárbol. 29 | 30 | \begin{code} 31 | height :: (Integral b) => Tree a -> b 32 | height Empty = 0 33 | height (Node x lft rgt) = 1 + max (height lft) (height rgt) 34 | \end{code} 35 | 36 | El *preorden*, *inorden* y *postorden* surgen también directamente con 37 | recursividad. El caso trivial es la lista vacía, y en otro caso, sólo hay que 38 | colocar el nodo y reordenar los órdenes de los subárboles. 39 | 40 | \begin{code} 41 | preorder :: Tree a -> [a] 42 | preorder Empty = [] 43 | preorder (Node x lft rgt) = preorder lft <> [x] <> preorder rgt 44 | \end{code} 45 | 46 | 47 | Inserción ordenada 48 | ----------------- 49 | 50 | Vamos a usar los árboles para implementar el algoritmo de ordenación 51 | `treesort`. Para ello debemos empezar creando árboles binarios ordenados, lo que 52 | hacemos insertando un elemento ordenadamente sobre el árbol. En el caso vacío, 53 | creamos un árbol de un elemento. 54 | 55 | \begin{code} 56 | insert :: (Ord a) => Tree a -> a -> Tree a 57 | insert Empty x = Node x Empty Empty 58 | \end{code} 59 | 60 | En el caso general, lo comparamos con 61 | el elemento del nodo y lo insertamos en el árbol derecho o izquierdo según el 62 | resultado de la comparación. 63 | 64 | \begin{code} 65 | insert (Node y lf rg) x 66 | | x <= y = Node y (insert lf x) rg 67 | | otherwise = Node y lf (insert rg x) 68 | \end{code} 69 | 70 | Ahora insertamos una lista completa en un árbol usando `foldl`. Vamos insertando 71 | cada elemento sobre el árbol vacío. 72 | 73 | \begin{code} 74 | toTree :: (Ord a) => [a] -> Tree a 75 | toTree = foldl insert Empty 76 | \end{code} 77 | 78 | Finalmente, el algoritmo de ordenación consiste en pasar la lista a árbol 79 | binario y volver a pasarlo a una lista de nuevo. 80 | 81 | \begin{code} 82 | treesort :: (Ord a) => [a] -> [a] 83 | treesort = preorder . foldl insert Empty 84 | \end{code} 85 | 86 | 87 | Completando los árboles 88 | ------------------ 89 | 90 | Vamos hacer a los árboles instancias de la clase `Eq`. 91 | Podemos delegar la tarea en el compilador incluyendo `deriving Eq` en la 92 | definición, pero vamos a escribirlo nosotros mismos. 93 | 94 | \begin{code} 95 | instance (Eq a) => Eq (Tree a) where 96 | Empty == Empty = True 97 | (Node x xl xr) == Empty = False 98 | (Node x xl xr) == (Node y yl yr) = and [x==y, xl==yl, xr==yr] 99 | \end{code} 100 | 101 | Inmediatamente podemos usar `(/=)` en árboles. 102 | -------------------------------------------------------------------------------- /Haskell Literario/fibonacci.lhs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fibonacci. Listas infinitas 3 | author: Pablo Baeyens, Mario Román 4 | --- 5 | 6 | Listas infinitas 7 | ---------------- 8 | 9 | \begin{code} 10 | import Control.Monad 11 | \end{code} 12 | 13 | Gracias a la evaluación perezosa de Haskell podemos definir listas infinitas 14 | sin que haya problema. Recursivamente, podemos usar funciones con *punto fijo*: 15 | 16 | \begin{code} 17 | naturals = 1 : map (+1) naturals 18 | \end{code} 19 | 20 | **¿Por qué funciona esta definición?** Cuando le pedimos el primer elemento de 21 | la lista, obviamente nos dará `1`; si le pedimos el segundo, sólo necesitará 22 | conocer el primero para calcularlo. Podemos usar `naturals` en su propia 23 | definición porque nunca los llegamos a necesitar todos. 24 | 25 | En Haskell, puede usarse directamente `[1..]` para notar esa lista infinita. 26 | 27 | Además podemos seguir manipulando listas infinitas para crear otras listas 28 | infinitas. Si `zipWith (+)` funciona con listas finitas uniéndolas mediante el 29 | operador: 30 | 31 | ~~~Haskell 32 | zipWith (+) [1,2,3] [1,2,3] == [2,4,6] 33 | ~~~ 34 | 35 | Funcionará también con listas infinitas: 36 | 37 | \begin{code} 38 | evenNumbers = zipWith (+) naturals naturals 39 | \end{code} 40 | 41 | 42 | Sucesión de Fibonacci 43 | ------------------- 44 | 45 | La forma obvia de calcular la sucesión de Fibonacci es mediante recursividad 46 | sobre los naturales. 47 | 48 | \begin{code} 49 | fib' 0 = 1 50 | fib' 1 = 1 51 | fib' n = fib' (n-1) + fib' (n-2) 52 | \end{code} 53 | 54 | Es, sin embargo, muy poco eficiente. Hay que volver a calcular todas las sumas 55 | cada vez que se calcula un término. Sería más útil tener una lista infinita 56 | de los términos de la sucesión, y tomar el que necesitáramos cada vez con el 57 | operador `!!`. [^hwiki-fib] 58 | 59 | \begin{code} 60 | fib n = fibs !! n 61 | \end{code} 62 | 63 | [^hwiki-fib]: The Fibonacci Sequence. [Haskell wiki](https://wiki.haskell.org/The_Fibonacci_sequence). 64 | 65 | La definición de Fibonacci usará recursión de punto fijo, 66 | ocupará ahora una línea y tendrá eficiencia lineal. 67 | 68 | \begin{code} 69 | fibs = 1 : 1 : zipWith (+) fibs (tail fibs) 70 | \end{code} 71 | 72 | **¿Por qué funciona esta definición?** Lo que estamos haciendo es sumarla contra 73 | sí misma desplazada una posición; la suma es algo así: 74 | 75 | ~~~haskell 76 | 1 : 1 : 2 : 3 : 5 : 8 : ... 77 | + 1 : 1 : 2 : 3 : 5 : ... 78 | -------------------------------- 79 | 1 : 2 : 3 : 5 : 8 : 13 .... 80 | ~~~ 81 | 82 | 83 | Ejemplo 84 | ---------------- 85 | 86 | Este programa muestra el crecimiento de una sucesión de fibonacci 87 | por la terminal: 88 | 89 | \begin{code} 90 | main :: IO () 91 | main = mapM_ (\n -> getLine >> putStrLn (replicate n '#')) fibs 92 | \end{code} 93 | -------------------------------------------------------------------------------- /Haskell Literario/hask-std.lhs: -------------------------------------------------------------------------------- 1 | --- 2 | title: La categoría Hask 3 | author: Pablo Baeyens, Mario Román 4 | --- 5 | 6 | Los tipos como categoría 7 | ---------------- 8 | 9 | La categoría **Hask** es la que toma a los tipos de Haskell como objetos y a las 10 | funciones de un tipo a otro como los morfismos entre ellos. Podemos comprobar 11 | que cumplen la definición de categoría: 12 | 13 | ```Haskell 14 | -- La composición de funciones es asociativa 15 | f . (g . h) === (f . g) . h 16 | -- Hay un morfismo identidad para cualquier objeto 17 | id . f === f === f . id 18 | ``` 19 | 20 | Para usarla tendremos que excluir algunos casos extremos, como funciones 21 | definibles que no terminan nunca o la instancia `undefined`. 22 | Estos detalles pueden consultarse en la wiki de Haskell. [^hask-wiki] 23 | 24 | [^hask-wiki]: Hask. [Haskell wiki](https://wiki.haskell.org/Hask). 25 | 26 | \begin{code} 27 | import Prelude() 28 | \end{code} 29 | 30 | 31 | Objetos inicial y final 32 | ------------------- 33 | 34 | El tipo **final** de la categoría es aquel para el que existe una única 35 | función desde cualquier otro tipo. Será isomorfo a `()`. 36 | 37 | \begin{code} 38 | unit :: a -> () 39 | unit _ = () 40 | \end{code} 41 | 42 | Esta función existe desde cualquier tipo, y no puede existir ninguna otra 43 | porque sólo tenemos una forma de construir una instancia de `()`. 44 | 45 | 46 | El tipo **inicial** de la categoría es aquel para el que existe una única 47 | función hacia cualquier otro tipo. Será isomorfo a `Void`, el tipo vacío 48 | que definimos con constructores autorreferentes; nunca habrá forma de construirlo. 49 | 50 | \begin{code} 51 | data Void = Void Void 52 | 53 | absurd :: Void -> a 54 | absurd (Void a) = absurd a 55 | \end{code} 56 | 57 | Nótese que no hay que definir nada más para la función `absurd`. Hemos usado 58 | `pattern matching` contra todos los constructores de `Void`. Que es la única función 59 | posible es obvio porque la única forma de conseguir un tipo cualquiera desde Void 60 | es con la propia función `absurd`. 61 | 62 | 63 | Productos y coproductos 64 | ------------------ 65 | 66 | El **producto** de dos tipos lo generamos con el constructor de tipos 67 | `(,)`. Cualesquiera dos tipos tienen un producto en esta categoría. Las 68 | proyecciones serán `fst` y `snd`. 69 | 70 | \begin{code} 71 | fst :: (a,b) -> a 72 | fst (x,y) = x 73 | 74 | snd :: (a,b) -> b 75 | snd (x,y) = y 76 | \end{code} 77 | 78 | Y otro tipo con morfismos hacia ambos podrá descomponerse a través del 79 | producto. 80 | 81 | \begin{code} 82 | (&&&) :: (c -> a) -> (c -> b) -> (c -> (a,b)) 83 | (&&&) f g = (\x -> (f x, g x)) 84 | \end{code} 85 | 86 | 87 | El **coproducto** de dos tipos lo generamos con el constructor de tipos 88 | `Either`. Cualesquiera dos tipos tienen un coproducto en esta categoría. 89 | Las coproyecciones serán `Left` y `Right`. 90 | 91 | \begin{code} 92 | data Either a b = Left a | Right b 93 | \end{code} 94 | 95 | Y otro tipo con morfismos desde ambos podrá descomponerlos a través del 96 | coproducto. 97 | 98 | \begin{code} 99 | either :: (a -> c) -> (b -> c) -> (Either a b -> c) 100 | either f g (Left x) = f x 101 | either f g (Right y) = g y 102 | \end{code} 103 | 104 | 105 | Cartesianamente cerrada 106 | ------------------ 107 | 108 | La categoría **Hask** es cerrada respecto a la estructura de monoide que tiene 109 | el producto categórico de tipos. Podemos ver que: 110 | 111 | * `((),a)` es isomorfo a `a` 112 | * `(a,(b,c))` es isomorfo a `((a,b),c)` 113 | 114 | Teniendo la estructura de monoide con el producto. 115 | 116 | \begin{code} 117 | prod_unit :: ((),a) -> a 118 | prod_unit ((),x) = x 119 | 120 | prod_assoc :: (a,(b,c)) -> ((a,b),c) 121 | prod_assoc (x,(y,z)) = ((x,y),z) 122 | \end{code} 123 | 124 | 125 | Funtores 126 | ------------------ 127 | 128 | Los constructores de tipos de la clase `Functor` son endofuntores de esta 129 | categoría. Un functor `f` se aplica sobre los tipos como `f a` y sobre los 130 | morfismos con `fmap g`. 131 | 132 | Las leyes de los functores deben cumplirse al definirlos: 133 | 134 | ``` Haskell 135 | fmap id == id 136 | fmap (f . g) == fmap f . fmap g 137 | ``` 138 | 139 | 140 | Lema de Yoneda 141 | -------------------- 142 | 143 | La formulación en teoría de categorías del lema de Yoneda nos dice que hay una 144 | correspondencia biyectiva entre transformaciones naturales desde el funtor 145 | $Hom(A,-)$ a $F$ y $F(A)$, para cualquier funtor $F$ que vaya a la categoría 146 | **Set**: 147 | 148 | $$ Nat(Hom(A,-),F) \cong F(A) $$ 149 | 150 | Este resultado, en tipos de Haskell se traduce en que equivalen los dos tipos 151 | siguientes: 152 | 153 | ```Haskell 154 | (a -> b) -> f b ~~ f a 155 | ``` 156 | 157 | Donde `a` es algún tipo pero `b` es una variable arbitraria de tipo. De manera 158 | más exacta, debe escribirse como: 159 | 160 | ```Haskell 161 | forall b . (a -> b) -> f b ~~ f a 162 | ``` 163 | 164 | Pueden encontrarse en las referencias una demostración y una explicación en mayor 165 | detalle. [^bartosz-yoneda] 166 | 167 | [^bartosz-yoneda]: Understanding Yoneda. [Bartosz Milewski](http://bartoszmilewski.com/2013/05/15/understanding-yoneda/). 168 | -------------------------------------------------------------------------------- /Haskell Literario/hask.lhs: -------------------------------------------------------------------------------- 1 | --- 2 | title: La categoría Hask 3 | author: Pablo Baeyens, Mario Román 4 | --- 5 | 6 | Los tipos como categoría 7 | ---------------- 8 | 9 | La categoría **Hask** es la que toma a los tipos de Haskell como objetos y a las 10 | funciones de un tipo a otro como los morfismos entre ellos. Podemos comprobar 11 | que cumplen la definición de categoría: 12 | 13 | ~~~Haskell 14 | -- La composición de funciones es asociativa 15 | f . (g . h) === (f . g) . h 16 | -- Hay un morfismo identidad para cualquier objeto 17 | id . f === f === f . id 18 | ~~~ 19 | 20 | Para usarla tendremos que excluir algunos casos extremos, como funciones 21 | definibles que no terminan nunca o la instancia `undefined`. 22 | Estos detalles pueden consultarse en la wiki de Haskell. [^hask-wiki] 23 | 24 | [^hask-wiki]: Hask. [Haskell wiki](https://wiki.haskell.org/Hask). 25 | 26 | \begin{code} 27 | {-# LANGUAGE EmptyDataDecls, EmptyCase #-} 28 | import Prelude() 29 | \end{code} 30 | 31 | 32 | Objetos inicial y final 33 | ------------------- 34 | 35 | El tipo **final** de la categoría es aquel para el que existe una única 36 | función desde cualquier otro tipo. Será isomorfo a `()`. 37 | 38 | \begin{code} 39 | unit :: a -> () 40 | unit _ = () 41 | \end{code} 42 | 43 | Esta función existe desde cualquier tipo, y no puede existir ninguna otra 44 | porque sólo tenemos una forma de construir una instancia de `()`. 45 | 46 | 47 | El tipo **inicial** de la categoría es aquel para el que existe una única 48 | función hacia cualquier otro tipo. Será isomorfo a `Void`, el tipo vacío 49 | que definimos sin constructores; nunca habrá forma de construirlo. 50 | 51 | \begin{code} 52 | data Void 53 | 54 | absurd :: Void -> a 55 | absurd v = case v of {} 56 | \end{code} 57 | 58 | Nótese que no hay que definir nada más para la función `absurd`. Hemos usado 59 | `pattern matching` contra todos los constructores de `Void`. Que es la única función 60 | posible es obvio por esto mismo. 61 | 62 | 63 | Productos y coproductos 64 | ------------------ 65 | 66 | El **producto** de dos tipos lo generamos con el constructor de tipos 67 | `(,)`. Cualesquiera dos tipos tienen un producto en esta categoría. Las 68 | proyecciones serán `fst` y `snd`. 69 | 70 | \begin{code} 71 | fst :: (a,b) -> a 72 | fst (x,y) = x 73 | 74 | snd :: (a,b) -> b 75 | snd (x,y) = y 76 | \end{code} 77 | 78 | Y otro tipo con morfismos hacia ambos podrá descomponerse a través del 79 | producto. 80 | 81 | \begin{code} 82 | (&&&) :: (c -> a) -> (c -> b) -> (c -> (a,b)) 83 | (&&&) f g = (\x -> (f x, g x)) 84 | \end{code} 85 | 86 | 87 | El **coproducto** de dos tipos lo generamos con el constructor de tipos 88 | `Either`. Cualesquiera dos tipos tienen un coproducto en esta categoría. 89 | Las coproyecciones serán `Left` y `Right`. 90 | 91 | \begin{code} 92 | data Either a b = Left a | Right b 93 | \end{code} 94 | 95 | Y otro tipo con morfismos desde ambos podrá descomponerlos a través del 96 | coproducto. 97 | 98 | \begin{code} 99 | either :: (a -> c) -> (b -> c) -> (Either a b -> c) 100 | either f g (Left x) = f x 101 | either f g (Right y) = g y 102 | \end{code} 103 | 104 | 105 | Cartesianamente cerrada 106 | ------------------ 107 | 108 | La categoría **Hask** es cerrada respecto a la estructura de monoide que tiene 109 | el producto categórico de tipos. Podemos ver que: 110 | 111 | * `((),a)` es isomorfo a `a` 112 | * `(a,(b,c))` es isomorfo a `((a,b),c)` 113 | 114 | Teniendo la estructura de monoide con el producto. 115 | 116 | \begin{code} 117 | prod_unit :: ((),a) -> a 118 | prod_unit ((),x) = x 119 | 120 | prod_assoc :: (a,(b,c)) -> ((a,b),c) 121 | prod_assoc (x,(y,z)) = ((x,y),z) 122 | \end{code} 123 | 124 | 125 | Funtores 126 | ------------------ 127 | 128 | Los constructores de tipos de la clase `Functor` son endofuntores de esta 129 | categoría. Un functor `f` se aplica sobre los tipos como `f a` y sobre los 130 | morfismos con `fmap g`. 131 | 132 | Las leyes de los functores deben cumplirse al definirlos: 133 | 134 | ``` Haskell 135 | fmap id == id 136 | fmap (f . g) == fmap f . fmap g 137 | ``` 138 | 139 | 140 | Lema de Yoneda 141 | -------------------- 142 | 143 | La formulación en teoría de categorías del lema de Yoneda nos dice que hay una 144 | correspondencia biyectiva entre transformaciones naturales desde el funtor 145 | $Hom(A,-)$ a $F$ y $F(A)$, para cualquier funtor $F$ que vaya a la categoría 146 | **Set**: 147 | 148 | $$ Nat(Hom(A,-),F) \cong F(A) $$ 149 | 150 | Este resultado, en tipos de Haskell se traduce en que equivalen los dos tipos 151 | siguientes: 152 | 153 | ```Haskell 154 | (a -> b) -> f b ~~ f a 155 | ``` 156 | 157 | Donde `a` es algún tipo pero `b` es una variable arbitraria de tipo. De manera 158 | más exacta, debe escribirse como: 159 | 160 | ```Haskell 161 | forall b . (a -> b) -> f b ~~ f a 162 | ``` 163 | 164 | Pueden encontrarse en las referencias una demostración y una explicación en mayor 165 | detalle. [^bartosz-yoneda] 166 | 167 | [^bartosz-yoneda]: Understanding Yoneda. [Bartosz Milewski](http://bartoszmilewski.com/2013/05/15/understanding-yoneda/). 168 | -------------------------------------------------------------------------------- /Haskell Literario/makefile: -------------------------------------------------------------------------------- 1 | all: pdfs execs 2 | 3 | pdfs: bintree.pdf hask.pdf fibonacci.pdf monoides.pdf quicksort.pdf 4 | execs: bintree hask fibonacci monoides quicksort 5 | 6 | %.pdf: %.lhs 7 | pandoc --to latex --from markdown+lhs $< -o $@ 8 | 9 | %: %.lhs 10 | ghc --make $< -o $@ 11 | -------------------------------------------------------------------------------- /Haskell Literario/monoides.lhs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Monoides 3 | author: Pablo Baeyens, Mario Román 4 | --- 5 | 6 | La clase `Monoid` 7 | ---------------- 8 | 9 | Las clases de tipos permiten generalizar el comportamiento de un conjunto de tipos 10 | a partir de una interfaz común: la clase `Eq` incluye los tipos que permiten comparar 11 | por igualdad, la clase `Ord` aquellos que admiten una relación de orden... 12 | 13 | La clase [`Monoid`](http://hackage.haskell.org/package/base-4.7.0.2/docs/Data-Monoid.html) 14 | permite agrupar aquellos tipos `T` que sean un monoide; es decir, que tengan una 15 | operación binaria `<> :: T -> T -> T` tal que: 16 | 17 | 1. Es **asociativa**: `(a <> b) <> c == a <> (b <> c)`. 18 | *Ejemplo*: La suma, aunque no la resta: $(3 - 2) - 1 \neq 3 - (2 - 1)$. 19 | 2. Existe un **elemento neutro**: `a <> mempty == a == mempty <> a`. 20 | *Ejemplo*: $0$ con respecto de la suma. La exponenciación no tiene. 21 | 22 | El ejemplo más sencillo de monoide es el tipo `()` con `a <> b = ()`. 23 | Para empezar a utilizarlos, importamos el módulo que los define 24 | y otros módulos que usaremos luego: 25 | 26 | \begin{code} 27 | {-# LANGUAGE FlexibleInstances, OverlappingInstances #-} 28 | import Data.Monoid 29 | import Control.Monad.Writer 30 | import Data.Tree 31 | \end{code} 32 | 33 | Además, este módulo define la función `mconcat :: [m] -> m` que se define: 34 | 35 | ~~~haskell 36 | mconcat = foldr (<>) mempty 37 | ~~~ 38 | 39 | Esta nos permite reducir listas de monoides. 40 | 41 | Algunos ejemplos de monoides son: 42 | 43 | Listas: [a] 44 | ----------- 45 | 46 | En este caso, `<> = (++)` y `mempty = []`. Podemos comprobarlo con algunos ejemplos: 47 | 48 | ~~~haskell 49 | ghci> [1,2] ++ [3,4] ++ [5,6] 50 | [1,2,3,4,5,6] 51 | ghci> [1,2] <> [3,4] <> [5,6] 52 | [1,2,3,4,5,6] 53 | ghci> [1,2,3,4] <> mempty 54 | [1,2,3,4] 55 | ~~~ 56 | 57 | `Sum` y `Product` 58 | ----------------- 59 | 60 | Los tipos numéricos permiten dos operaciones binarias con las que forman un monoide: 61 | la suma y el producto. Para diferenciarlos se definen, dado un tipo numérico `a`, 62 | tipos que los envuelven: 63 | 64 | - `Sum`: `Sum a <> Sum b = Sum (a + b)` y `mempty = Sum 0`. 65 | - `Product`: `Product a <> Product b = Product (a * b)` y `mempty = Product 1`. 66 | 67 | Las funciones `getSum` y `getProduct` permiten extraer el número del tipo. De esta 68 | forma podemos definir: 69 | 70 | \begin{code} 71 | sumar, producto :: Num a => [a] -> a 72 | sumar = getSum . mconcat . map Sum 73 | producto = getProduct . mconcat . map Product 74 | \end{code} 75 | 76 | Estas son equivalentes a las funciones `sum` y `product` incluidas en el `Prelude`. 77 | 78 | `Endo` 79 | ------ 80 | 81 | `Endo a` envuelve endomorfismos sobre un tipo `a` (funciones `a -> a`) y define un 82 | monoide: 83 | 84 | - `Endo f <> Endo g = Endo (f . g)`: la composición. 85 | - `mempty = Endo id`: la función identidad, `id x = x`. 86 | 87 | Extraemos la función con `appEndo :: Endo a -> (a -> a)`. 88 | Utilizando este monoide podemos componer una lista de funciones fácilmente: 89 | 90 | \begin{code} 91 | fs :: Num a => [Endo a] 92 | fs = [Endo (*3), Endo (+2), Endo negate, Endo (37-)] 93 | 94 | g :: Num a => a -> a 95 | g = appEndo (mconcat fs) 96 | \end{code} 97 | 98 | De esta forma forma tenemos `g x = (negate (37 - x) + 2) * 3`. 99 | 100 | Kleisi 101 | ------ 102 | 103 | De forma análoga a `Endo`, podemos definir un monoide sobre las 104 | funciones `a -> m a` con `m` una mónada. 105 | 106 | La composición es `(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c`, y 107 | `mempty` es simplemente `return`: 108 | 109 | \begin{code} 110 | instance Monad m => Monoid (a -> m a) where 111 | mempty = return 112 | mappend = (>=>) 113 | \end{code} 114 | 115 | Crear un monoide 116 | ------------------ 117 | Podemos definir una función binaria sobre nuestros árboles y hacerlos un monoide. 118 | La operación será introducir ordenadamente todos los elementos de un árbol en el otro. 119 | 120 | \begin{code} 121 | --instance (Ord a) => Monoid (Tree a) where 122 | -- at <> bt = 123 | \end{code} 124 | 125 | La mónada Writer 126 | ---------------- 127 | 128 | La mónada `Writer` nos permite guardar un registro de las acciones que realizamos. 129 | **¿Cómo se define esta mónada?**: 130 | 131 | - En primer lugar necesitamos un **monoide**, que será el tipo de nuestro registro. 132 | - `return` introduce el elemento en su mínimo contexto. De esta forma, el mínimo 133 | registro es `mempty`: `return x = Writer (x, mempty)` 134 | - Para definir el *bind* necesitamos una función que extraiga el tipo: `runWriter` 135 | ~~~Haskell 136 | x >>= f = 137 | let (a, m) = runWriter x 138 | (b, m') = runWriter (f a) 139 | in Writer (b, m <> m') 140 | ~~~ 141 | 142 | De esta forma unimos ambos registros. 143 | 144 | Veamos un ejemplo. Podemos introducir algo en la mónada `Writer` utilizando la 145 | función `writer`: 146 | 147 | \begin{code} 148 | suma n x = writer (x + n, ["Suma " ++ show n]) 149 | mult n x = writer (x * n, ["Multiplica por " ++ show n]) 150 | resta n x = writer (x - n, ["Resta " ++ show n]) 151 | \end{code} 152 | 153 | Estas funciones realizan una operación sobre un número y guardan en el registro 154 | la operación realizada. 155 | 156 | Utilizando el monoide que creamos antes componemos una serie de estas funciones: 157 | 158 | \begin{code} 159 | h = mconcat [suma 3, suma 2, mult 4, resta 24] 160 | \end{code} 161 | 162 | Y para probar nuestra función, creamos un programa sencillo: 163 | 164 | \begin{code} 165 | main = do 166 | putStrLn "Introduzca un número: " 167 | n <- readLn :: IO Int 168 | let (resultado, registro) = runWriter (h n) 169 | putStrLn $ "El resultado es " ++ show resultado 170 | putStrLn $ "\nLas operaciones realizadas han sido:\n" ++ unlines registro 171 | \end{code} 172 | -------------------------------------------------------------------------------- /Haskell Literario/quicksort.lhs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quicksort 3 | author: Pablo Baeyens, Mario Román 4 | --- 5 | 6 | Implementación 7 | ---------------- 8 | 9 | El algoritmo Quicksort toma el primer elemento de la lista, coloca a su izquierda 10 | los menores que él y a su derecha los mayores, y vuelve a aplicarse a ambos 11 | lados. 12 | 13 | Lo definimos recursivamente. La lista vacía está ya ordenada: 14 | 15 | \begin{code} 16 | qsort [] = [] 17 | \end{code} 18 | 19 | Dada una lista no vacía, tomamos el elemento inicial y colocamos a un lado y 20 | otro de él las listas de menores y mayores, respectivamente. Ordenamos esas 21 | listas. 22 | 23 | \begin{code} 24 | qsort (x:xs) = qsort [y | y<-xs, y<=x] 25 | <> [x] 26 | <> qsort [y | y<-xs, y>x] 27 | \end{code} 28 | 29 | 30 | Ejemplo 31 | --------------- 32 | Este programa ordena una lista de números: 33 | \begin{code} 34 | main :: IO () 35 | main = do putStrLn "Introduzca números a ordenar separados por espacios: " 36 | contents <- getLine 37 | let numbers = map read $ words contents :: [Integer] 38 | print $ qsort numbers 39 | \end{code} 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /PrimeraParte/1-intro.hs: -------------------------------------------------------------------------------- 1 | -- Esto es un comentario 2 | 3 | powerLevel = 9001 4 | 5 | over9000 = powerLevel > 9000 6 | 7 | hola = "Hola" 8 | adios = "Adiós" 9 | 10 | holaMundo = (if over9000 then hola else adios) <> ", 🌍 !" 11 | 12 | main = putStrLn holaMundo 13 | -------------------------------------------------------------------------------- /PrimeraParte/2-tipos.hs: -------------------------------------------------------------------------------- 1 | powerLevel :: Int 2 | powerLevel = 9001 3 | 4 | over9000 :: Bool 5 | over9000 = powerLevel > 9000 6 | 7 | holaMundo :: String 8 | holaMundo = (if over9000 then "Hola" else "Adiós") <> ", 🌍!" 9 | 10 | brillicos :: Char 11 | brillicos = '✨' 12 | 13 | main :: IO () 14 | main = putStrLn holaMundo 15 | 16 | e :: Double 17 | e = exp 1 18 | 19 | -- ¿-(x+3) o -x+3? 20 | f :: Int -> Int 21 | f x = negate x + 3 22 | 23 | -- Podemos especificar o no el tipo de nand 24 | nand :: Bool -> Bool -> Bool 25 | nand x y = not (x && y) 26 | -------------------------------------------------------------------------------- /PrimeraParte/3-variablesTipo.hs: -------------------------------------------------------------------------------- 1 | -- :t id? 2 | id' x = x 3 | 4 | const' :: a -> b -> a 5 | const' x y = x 6 | 7 | fst' :: (a,b) -> a 8 | fst' (x,y) = x 9 | 10 | swap (x,y) = (y,x) 11 | 12 | 13 | -- shimweasel.com/2015/02/17/typed-holes-for-beginners 14 | g :: (a -> b) -> (a,c) -> (c,b) 15 | g x y = _resultado 16 | -------------------------------------------------------------------------------- /PrimeraParte/4-patrones.hs: -------------------------------------------------------------------------------- 1 | {- Reconocimiento de patrones -} 2 | 3 | not' :: Bool -> Bool 4 | not' True = False 5 | not' False = True 6 | 7 | -- :t ifThenElse? 8 | ifThenElse True x _ = x 9 | ifThenElse False _ y = y 10 | 11 | -- El orden es importante 12 | esNulo :: Int -> Bool 13 | esNulo 0 = True 14 | esNulo _ = False -- _ cuando no usamos el argumento 15 | 16 | factorialErroneo :: Int -> Int 17 | factorialErroneo n = n * factorialErroneo (n - 1) 18 | factorialErroneo 0 = 1 19 | -------------------------------------------------------------------------------- /PrimeraParte/5-curry.hs: -------------------------------------------------------------------------------- 1 | suma5 :: Int -> Int 2 | suma5 = (5+) 3 | 4 | mult4 :: Int -> Int 5 | mult4 = (4*) 6 | 7 | -- 8 | g :: Int -> Int 9 | g = suma5 . mult4 -- g x = 4*x + 5 10 | -------------------------------------------------------------------------------- /PrimeraParte/5-curry.py: -------------------------------------------------------------------------------- 1 | 2 | # En Haskell: 3 | # suma x y = x + y 4 | 5 | # En Python: 6 | 7 | def suma(x): 8 | def sumax(y): 9 | return x + y 10 | return sumax 11 | 12 | print suma(2) 13 | print suma(2)(3) 14 | -------------------------------------------------------------------------------- /PrimeraParte/6-listas.hs: -------------------------------------------------------------------------------- 1 | l1 :: [Int] 2 | l1 = [1,2,3] 3 | 4 | l2 :: [Int] 5 | l2 = l1 <> [4,5] -- Concatenar 6 | 7 | l3 :: [Int] 8 | l3 = 0 : l2 -- Anteponer un elemento 9 | -- l3 == 0:(1:(2:(3:(4:(5:[]))))) 10 | 11 | -- :t l4 ? 12 | l4 = [] 13 | 14 | {- Funciones sobre listas -} 15 | 16 | head' :: [a] -> a 17 | -- Primer elemento 18 | head' [] = error "Lista vacía" 19 | head' (x:xs) = _head 20 | 21 | length' :: [a] -> Int 22 | -- Longitud 23 | -- ¿Por qué es ineficiente? 24 | length' [] = 0 25 | length' (x:xs) = 1 + length' xs 26 | 27 | repeat' :: a -> [a] 28 | repeat' a = a : repeat' a 29 | 30 | (!!!) :: [a] -> Int -> a 31 | [] !!! _ = error "Índice demasiado grande" 32 | (x:_) !!! 0 = x 33 | (_:xs) !!! n = xs !!! (n-1) 34 | -------------------------------------------------------------------------------- /PrimeraParte/7-ordenSup.hs: -------------------------------------------------------------------------------- 1 | flip' :: (a -> b -> c) -> b -> a -> c 2 | flip' f y x = f x y 3 | 4 | 5 | ifThenElse' :: Bool -> a -> a -> a 6 | ifThenElse' True = _ifTrue 7 | ifThenElse' False = _ifFalse 8 | 9 | 10 | -- map f [a1, a2, ..., an] = 11 | -- [f a1, f a2, ..., f an] 12 | map' :: (a -> b) -> [a] -> [b] 13 | map' f [] = [] 14 | map' f (x:xs) = f x : map f xs 15 | 16 | suma1 :: [Int] -> [Int] 17 | suma1 = map (+1) 18 | 19 | exclama :: [String] -> [String] 20 | exclama = map (<>"!") 21 | 22 | 23 | -- foldr (⊕) z [a1,...,an] = 24 | -- a1 ⊕ (a2 ⊕ (... ⊕ (an ⊕ z))) 25 | foldr' :: (a -> b -> b) -> b -> [a] -> b 26 | foldr' g z [] = z 27 | foldr' g z (x:xs) = x `g` foldr' g z xs 28 | 29 | sum' :: [Int] -> Int 30 | sum' = foldr (+) 0 31 | 32 | concat' :: [[a]] -> [a] 33 | concat' = foldr (<>) [] 34 | 35 | --- Hueco en el tipo 36 | filter' :: _ -> [a] -> [a] 37 | filter' p [] = [] 38 | filter' p (x:xs) = if p x then x:ys else ys 39 | where ys = filter' p xs 40 | -------------------------------------------------------------------------------- /PrimeraParte/7.2-foldr.hs: -------------------------------------------------------------------------------- 1 | -- foldr (⊕) z [a1,...,an] = 2 | -- a1 ⊕ (a2 ⊕ (... ⊕ (an ⊕ z))) 3 | -- catamorphism 4 | 5 | map'' :: (a -> b) -> [a] -> [b] 6 | map'' f = foldr _gMap _zMap 7 | 8 | filter'' :: (a -> Bool) -> [a] -> [a] 9 | filter'' p = foldr _gFilter _zFilter 10 | 11 | length' :: [a] -> Int 12 | length' = foldr _gLength _zLength 13 | 14 | -- Y más! Ver ejercicios 15 | -------------------------------------------------------------------------------- /PrimeraParte/8-tipos.hs: -------------------------------------------------------------------------------- 1 | 2 | {- Definición de tipos -} 3 | 4 | -- data Bool = False | True 5 | -- data Int = 6 | -- -9223372036854775808|...|-1|0|1|...|9223372036854775807 7 | 8 | 9 | -- Tipos enumerados 10 | data Forma = Triangulo | Cuadrado | Circulo -- :t Triangulo ? 11 | 12 | esPoligono :: Forma -> Bool 13 | esPoligono Triangulo = True 14 | esPoligono Cuadrado = True 15 | esPoligono Circulo = False 16 | 17 | 18 | -- Tipos con campos :t P ? 19 | data Persona = P String Int 20 | 21 | -- Obtener la edad de una persona 22 | getEdad :: Persona -> Int 23 | getEdad (P _ edad) = edad 24 | 25 | -- Tienen la misma edad? 26 | mismaEdad :: Persona -> Persona -> Bool 27 | mismaEdad (P _ e1) (P _ e2) = e1 == e2 28 | 29 | 30 | 31 | -- Varios constructores de datos 32 | data Color = RGB Double Double Double 33 | | HSV Double Double Double 34 | 35 | 36 | 37 | -- Tipos recursivos 38 | data Nat = Z | S Nat 39 | deriving (Eq,Show) 40 | 41 | suma :: Nat -> Nat -> Nat 42 | -- suma de naturales 43 | suma Z n = n 44 | suma (S n) m = S (suma n m) 45 | 46 | toInt :: Nat -> Int 47 | -- Pasar a entero 48 | toInt Z = 0 49 | toInt (S n) = 1 + toInt n 50 | 51 | 52 | data Quizas a = Nada | Algo a 53 | deriving (Eq,Show) 54 | 55 | mapList :: (a -> b) -> Quizas a -> Quizas b 56 | mapList f Nada = Nada 57 | mapList f (Algo x) = Algo (f x) 58 | 59 | 60 | data Pareja a b = Pareja a b 61 | deriving (Eq, Show) 62 | -------------------------------------------------------------------------------- /PrimeraParte/9-clases.hs: -------------------------------------------------------------------------------- 1 | {- No podemos demostrar que las instancias cumplen las propiedades-} 2 | 3 | {- 4 | Clase de los monoides 5 | Sujeto a las propiedades: 6 | 7 | · x <+> (y <+> z) = (x <+> y) <+> z 8 | · x <+> neutro = neutro <+> x = x 9 | -} 10 | 11 | class Monoide a where 12 | (<+>) :: a -> a -> a 13 | neutro :: a 14 | 15 | instance Monoide [a] where 16 | xs <+> ys = xs <> ys 17 | neutro = [] 18 | 19 | instance Monoide Int where 20 | x <+> y = x + y 21 | neutro = 0 22 | 23 | 24 | reduce :: (Monoide a) => [a] -> a 25 | reduce = foldr (<+>) neutro 26 | 27 | 28 | data Tree a = Empty | Node a (Tree a) (Tree a) 29 | deriving (Eq, Show) 30 | 31 | 32 | {- 33 | Clase de los funtores. 34 | Sujeto a las propiedades: 35 | 36 | · fmap id == id 37 | · fmap f . fmap g == fmap (f . g) 38 | -} 39 | class Funtor f where 40 | fmap' :: (a -> b) -> f a -> f b 41 | 42 | 43 | instance Funtor [] where 44 | fmap' f [] = [] 45 | fmap' f (x:xs) = f x : fmap' f xs 46 | 47 | 48 | instance Funtor Tree where 49 | fmap' f Empty = Empty 50 | fmap' f (Node a tLeft tRight) = Node (f a) (fmap' f tLeft) (fmap' f tRight) 51 | -------------------------------------------------------------------------------- /PrimeraParte/9.2-clases.hs: -------------------------------------------------------------------------------- 1 | {-#LANGUAGE DeriveFunctor, DeriveFoldable #-} 2 | 3 | data Tree a = Empty | Node a (Tree a) (Tree a) 4 | deriving (Eq, Show, Functor, Foldable) 5 | 6 | 7 | singleton x = Node x Empty Empty 8 | 9 | arbol :: Int -> Tree Int 10 | arbol 0 = singleton 1 11 | arbol n = Node 1 subarbol subarbol 12 | where subarbol = fmap (2*) (arbol (n-1)) 13 | -------------------------------------------------------------------------------- /PrimeraParte/PrimeraParte.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Haskell 101" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Este notebook está basado en el código de una charla para Haskell (con GHC 8 o superior) dada el día 10 de diciembre de 2016. Para una introducción más extensa puedes leer [estos apuntes](https://github.com/libreim/haskell/blob/master/apuntes/introHaskell.pdf) así como los recursos que enlazan. Idea original y código de [@pedritomelenas](https://github.com/pedritomelenas), con comentarios y modificaciones de [@mx-psi](https://github.com/mx-psi)." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Introducción" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "Haskell es un lenguaje de programación funcional puro con tipos fuertes y estáticos y evaluación perezosa. Un programa en Haskell se basa en una serie de definiciones en forma de ecuaciones. El compilador o intérprete evaluará cada expresión sustituyendo el lado izquierdo de la ecuación por el derecho, sustituyendo los argumentos si es necesario.\n", 29 | "\n", 30 | "Si **pruebas a descomentar la linea `a = 5`** obtendrás un error: las igualdades son definiciones y no asignaciones, y no podemos dar dos definiciones distintas de la misma cosa." 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "metadata": { 37 | "collapsed": false 38 | }, 39 | "outputs": [], 40 | "source": [ 41 | "a :: Int\n", 42 | "a = 42\n", 43 | "--a = 5\n", 44 | "\n", 45 | "f :: Int -> Int\n", 46 | "f x = x + 2\n", 47 | "\n", 48 | "b = f a + f a + f a\n" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "Como ves las funciones se escriben separando con espacios sus argumentos. En un lenguaje de programación imperativo no podemos en general optimizar el cálculo de `b`: debemos **calcular 3 veces `f a`** ya que podría devolver un valor aleatorio, comunicarse con el mundo real o cambiar variables globales. \n", 56 | "\n", 57 | "En Haskell podemos [razonar algebraicamente](https://stackoverflow.com/questions/210835) sobre nuestros programas y el compilador puede realizar toda clase de optimizaciones. **Situa el cursor en la siguiente celda y presiona `Ctrl+Enter` para evaluar `b`**." 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": { 64 | "collapsed": false 65 | }, 66 | "outputs": [], 67 | "source": [ 68 | "b" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "## El sistema de tipos" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "Los tipos en Haskell son **fuertes** y **estáticos**. Se conoce el tipo de cada expresión en tiempo de compilación y los *castings* deben ser explícitos. Esto puede tener algunos inconvenientes, sin embargo los tipos son **inferidos**. \n", 83 | "\n", 84 | "A continuación algunas expresiones con tipos básicos como caracteres o cadenas de caracteres. El tipo de una expresión `expresion` se indica `expresion :: Tipo`. El nombre de los tipos empieza por mayúscula." 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "metadata": { 91 | "collapsed": true 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "haskell :: String\n", 96 | "haskell = \"haskell.org/platform\"\n", 97 | "\n", 98 | "lambda :: Char\n", 99 | "lambda = 'λ' -- Permite Unicode\n", 100 | "\n", 101 | "e :: Double\n", 102 | "e = exp 1\n" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "El sistema de inferencia de tipos permite conocer el tipo de una expresión a partir de los tipos de las expresiones que lo constituyen. De esta forma el compilador puede deducir que la constante `b` definida anteriormente tiene tipo `Int`. **Puedes comprobar el tipo de `expresion` indicando `:t expresion`**:" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": { 116 | "collapsed": false 117 | }, 118 | "outputs": [], 119 | "source": [ 120 | ":t b" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "Expresar el tipo de cada función nos sirve a modo de documentación y lo haremos durante el resto de este notebook aunque no es necesario en la mayoría de los casos (puedes comprobarlo en el siguiente ejemplo que define la función `nand`). \n", 128 | "\n", 129 | "Cuando una función toma más de un argumento estos se separan por `->` (el por qué se explica en la sección de *currificación*)." 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": null, 135 | "metadata": { 136 | "collapsed": true 137 | }, 138 | "outputs": [], 139 | "source": [ 140 | "nand :: Bool -> Bool -> Bool\n", 141 | "nand x y = not (x && y)\n" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": { 148 | "collapsed": false 149 | }, 150 | "outputs": [], 151 | "source": [ 152 | ":t nand True False" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "## Variables de tipo" 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": {}, 165 | "source": [ 166 | "Algunas funciones no tienen por qué reducirse a un sólo tipo: la función `id` (la identidad), definida por la ecuación `id x = x` podría tomar `Int` como entrada, pero también `Char`, `String` o cualquier otro tipo que definamos. \n", 167 | "\n", 168 | "En estos casos Haskell utiliza **variables de tipo**, que pueden sustituirse por cualquier tipo. Así la función `id` tiene tipo $\\forall a: a \\to a$, ya que toma algo de un tipo arbitario $a$ y devuelve algo del mismo tipo. Las variables de tipo se indican **en minúscula**." 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "metadata": { 175 | "collapsed": false 176 | }, 177 | "outputs": [], 178 | "source": [ 179 | ":t id" 180 | ] 181 | }, 182 | { 183 | "cell_type": "markdown", 184 | "metadata": {}, 185 | "source": [ 186 | "En general podemos tener un número arbitrario de variables de tipo independientes: la función `const`, que toma dos argumentos y devuelve el primero tiene tipo $\\forall a \\; \\forall b: a \\to b \\to a$" 187 | ] 188 | }, 189 | { 190 | "cell_type": "markdown", 191 | "metadata": {}, 192 | "source": [ 193 | "_**Ejercicio**: Define la función `const`_" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "metadata": { 200 | "collapsed": false 201 | }, 202 | "outputs": [], 203 | "source": [ 204 | "-- Ya está definida, así que le ponemos otro nombre\n", 205 | "-- La comilla es un caracter válido para los identificadores\n", 206 | "const' :: a -> b -> a" 207 | ] 208 | }, 209 | { 210 | "cell_type": "markdown", 211 | "metadata": {}, 212 | "source": [ 213 | "## Patrones" 214 | ] 215 | }, 216 | { 217 | "cell_type": "markdown", 218 | "metadata": {}, 219 | "source": [ 220 | "Como hemos visto en las secciones anteriores podemos definir una función utilizando el esquema:\n", 221 | "```haskell\n", 222 | "f x1 x2 ... xn = ...\n", 223 | "```\n", 224 | "de tal forma que los argumentos quedan ligados a las variables `x1` a `xn`. Haskell permite también definir las funciones por casos en función del tipo que escojamos.\n", 225 | "\n", 226 | "En el siguiente ejemplo definimos la función `niega :: Bool -> Bool` que define la negación lógica:" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": null, 232 | "metadata": { 233 | "collapsed": true 234 | }, 235 | "outputs": [], 236 | "source": [ 237 | "niega True = False\n", 238 | "niega False = True" 239 | ] 240 | }, 241 | { 242 | "cell_type": "markdown", 243 | "metadata": {}, 244 | "source": [ 245 | "Definimos la función para cada posible instancia del tipo. El compilador entonces evaluará en orden cada ecuación hasta que encuentre una en la que encaje. \n", 246 | "\n", 247 | "Podemos combinar las variables y los patrones como en el siguiente predicado que comprueba si un número es cero:" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": { 254 | "collapsed": true 255 | }, 256 | "outputs": [], 257 | "source": [ 258 | "esCero :: Int -> Bool\n", 259 | "esCero 0 = True\n", 260 | "esCero _ = False" 261 | ] 262 | }, 263 | { 264 | "cell_type": "markdown", 265 | "metadata": {}, 266 | "source": [ 267 | "El símbolo `_` es una convención que indica que no va a utilizarse ese argumento." 268 | ] 269 | }, 270 | { 271 | "cell_type": "markdown", 272 | "metadata": {}, 273 | "source": [ 274 | "_**Ejercicio**: Define la función `factorial:: Int -> Int`_" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": null, 280 | "metadata": { 281 | "collapsed": true 282 | }, 283 | "outputs": [], 284 | "source": [ 285 | "factorial :: Int -> Int\n", 286 | "-- Necesitarás dos casos" 287 | ] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": null, 292 | "metadata": { 293 | "collapsed": true 294 | }, 295 | "outputs": [], 296 | "source": [ 297 | "factorial 20" 298 | ] 299 | }, 300 | { 301 | "cell_type": "markdown", 302 | "metadata": {}, 303 | "source": [ 304 | "_**Ejercicio**: Define la función `(&&) :: Bool -> Bool -> Bool` (conjunción lógica)_" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": null, 310 | "metadata": { 311 | "collapsed": true 312 | }, 313 | "outputs": [], 314 | "source": [ 315 | "-- Como esta función ya está definida le ponemos otro nombre:\n", 316 | "y :: Bool -> Bool -> Bool" 317 | ] 318 | }, 319 | { 320 | "cell_type": "code", 321 | "execution_count": null, 322 | "metadata": { 323 | "collapsed": false 324 | }, 325 | "outputs": [], 326 | "source": [ 327 | "-- Podemos llamar funciones de forma infija entre acentos graves\n", 328 | "True `y` False" 329 | ] 330 | }, 331 | { 332 | "cell_type": "markdown", 333 | "metadata": {}, 334 | "source": [ 335 | "## Currificación" 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": {}, 341 | "source": [ 342 | "Como hemos visto antes, las funciones con más de un argumento tienen un tipo de la forma `A -> (B -> C)`, en lugar del tipo `A×B -> C`. Esto se debe a la [currificación](https://en.wikipedia.org/wiki/Currying), la identificación entre las funciones:\n", 343 | "\n", 344 | "$$f : A \\times B \\to C \\qquad f(a,b) = c$$\n", 345 | "$$f : A \\to (B \\to C) \\qquad g = f(a), g(b) = c$$\n", 346 | "\n", 347 | "En lugar de tener una función que toma dos argumentos y devuelve un resultado, tenemos una función que toma un argumento y devuelve otra función que toma otro argumento para devolver el resultado. De esta forma podemos aplicar parcialmente funciones, como en el caso de la función `suma5`, que suma 5 a otra:" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": null, 353 | "metadata": { 354 | "collapsed": true 355 | }, 356 | "outputs": [], 357 | "source": [ 358 | "suma5 = (5+)" 359 | ] 360 | }, 361 | { 362 | "cell_type": "code", 363 | "execution_count": null, 364 | "metadata": { 365 | "collapsed": false 366 | }, 367 | "outputs": [], 368 | "source": [ 369 | "suma5 3" 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": {}, 375 | "source": [ 376 | "Aunque no es habitual quizás ayude ver un ejemplo equivalente en Python, definiendo de forma currificada una función que suma dos números:\n", 377 | "\n", 378 | "```python\n", 379 | "def suma(x):\n", 380 | " def sumax(y):\n", 381 | " return x + y\n", 382 | " return sumax\n", 383 | "\n", 384 | "```\n", 385 | "\n", 386 | "De esta forma `suma(2)` sería una función que suma 2, mientras que `suma(2)(3)` tendría el valor 5." 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "De esta forma podemos crear pequeñas funciones que componer para crear otras más complejas. Utilizando el operador `.` que compone funciones podemos crear por ejemplo una función que sume 12:" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": null, 399 | "metadata": { 400 | "collapsed": true 401 | }, 402 | "outputs": [], 403 | "source": [ 404 | "suma7 =(7+)" 405 | ] 406 | }, 407 | { 408 | "cell_type": "code", 409 | "execution_count": null, 410 | "metadata": { 411 | "collapsed": true 412 | }, 413 | "outputs": [], 414 | "source": [ 415 | "suma12 = suma5 . suma7" 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": null, 421 | "metadata": { 422 | "collapsed": false 423 | }, 424 | "outputs": [], 425 | "source": [ 426 | "suma12 9" 427 | ] 428 | }, 429 | { 430 | "cell_type": "markdown", 431 | "metadata": {}, 432 | "source": [ 433 | "_**Ejercicio**: Define una función que indique si un número no es cero haciendo uso de la composición._" 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": null, 439 | "metadata": { 440 | "collapsed": true 441 | }, 442 | "outputs": [], 443 | "source": [ 444 | "noEsCero :: Int -> Bool\n", 445 | "noEsCero = _" 446 | ] 447 | }, 448 | { 449 | "cell_type": "markdown", 450 | "metadata": {}, 451 | "source": [ 452 | "_**Ejercicio**: ¿Cuál es el tipo de la función `.`? Escribe su tipo y compruébalo en la siguiente celda._" 453 | ] 454 | }, 455 | { 456 | "cell_type": "code", 457 | "execution_count": null, 458 | "metadata": { 459 | "collapsed": false 460 | }, 461 | "outputs": [], 462 | "source": [ 463 | ":t (.)" 464 | ] 465 | }, 466 | { 467 | "cell_type": "markdown", 468 | "metadata": {}, 469 | "source": [ 470 | "## Listas" 471 | ] 472 | }, 473 | { 474 | "cell_type": "markdown", 475 | "metadata": {}, 476 | "source": [ 477 | "Las listas almacenan colecciones ordenadas de valores de un tipo homogéneo. Su tamaño no es fijo, es decir, listas de distintos tamaños pertenecen al mismo tipo.\n", 478 | "\n", 479 | "Una lista se escribe entre corchetes, separando sus elementos por comas. La lista vacía se escribe `[]`:" 480 | ] 481 | }, 482 | { 483 | "cell_type": "code", 484 | "execution_count": null, 485 | "metadata": { 486 | "collapsed": true 487 | }, 488 | "outputs": [], 489 | "source": [ 490 | "l1 :: [Int]\n", 491 | "l1 = [1,2,3]\n", 492 | "\n", 493 | "l2 = l1 <> [4,5] -- Concatenar" 494 | ] 495 | }, 496 | { 497 | "cell_type": "markdown", 498 | "metadata": {}, 499 | "source": [ 500 | "Como vemos, indicamos en el tipo que se trata de una lista de enteros. El operador `<>` permite concatenar dos listas, mientras que el operador `:` permite anteponer un elemento a otra lista:" 501 | ] 502 | }, 503 | { 504 | "cell_type": "code", 505 | "execution_count": null, 506 | "metadata": { 507 | "collapsed": false 508 | }, 509 | "outputs": [], 510 | "source": [ 511 | "0 : l2" 512 | ] 513 | }, 514 | { 515 | "cell_type": "markdown", 516 | "metadata": {}, 517 | "source": [ 518 | "_**Ejercicio**: ¿Cuál es el tipo de la lista vacía? Compruébalo_" 519 | ] 520 | }, 521 | { 522 | "cell_type": "code", 523 | "execution_count": null, 524 | "metadata": { 525 | "collapsed": false 526 | }, 527 | "outputs": [], 528 | "source": [ 529 | ":t []" 530 | ] 531 | }, 532 | { 533 | "cell_type": "markdown", 534 | "metadata": {}, 535 | "source": [ 536 | "Para definir funciones sobre listas utilizamos el reconocimiento de patrones. En este caso definimos una función que nos devuelve el primer elemento de una lista (si la lista es vacía devolverá un `error`). Utilizamos el constructor `:`, que como vimos antes antepone un elemento a una lista.\n", 537 | "\n", 538 | "Esta función viene ya definida como `head`:" 539 | ] 540 | }, 541 | { 542 | "cell_type": "code", 543 | "execution_count": null, 544 | "metadata": { 545 | "collapsed": false 546 | }, 547 | "outputs": [], 548 | "source": [ 549 | "cabeza :: [a] -> a\n", 550 | "cabeza [] = error \"Lista vacia\"\n", 551 | "cabeza (x:_) = x" 552 | ] 553 | }, 554 | { 555 | "cell_type": "code", 556 | "execution_count": null, 557 | "metadata": { 558 | "collapsed": false 559 | }, 560 | "outputs": [], 561 | "source": [ 562 | "cabeza l2" 563 | ] 564 | }, 565 | { 566 | "cell_type": "markdown", 567 | "metadata": {}, 568 | "source": [ 569 | "_**Ejercicio:** Define una función que devuelva la `cola` de una lista_" 570 | ] 571 | }, 572 | { 573 | "cell_type": "code", 574 | "execution_count": null, 575 | "metadata": { 576 | "collapsed": true 577 | }, 578 | "outputs": [], 579 | "source": [ 580 | "cola :: [a] -> [a]\n", 581 | "cola [] = error \"Lista vacia\"\n", 582 | "--- ..." 583 | ] 584 | }, 585 | { 586 | "cell_type": "markdown", 587 | "metadata": {}, 588 | "source": [ 589 | "Otro ejemplo es una función `longitud` que nos devuelva la longitud de una lista (finita). La longitud de una lista vacía es 0, mientras que la de una lista no vacía es uno más la longitud de su cola (la lista sin su primer elemento):" 590 | ] 591 | }, 592 | { 593 | "cell_type": "code", 594 | "execution_count": null, 595 | "metadata": { 596 | "collapsed": true 597 | }, 598 | "outputs": [], 599 | "source": [ 600 | "longitud :: [a] -> Int\n", 601 | "longitud [] = 0\n", 602 | "longitud (_:xs) = 1 + longitud xs" 603 | ] 604 | }, 605 | { 606 | "cell_type": "markdown", 607 | "metadata": {}, 608 | "source": [ 609 | "Si queremos calcular la longitud de `l1` el compilador hará algo equivalente a:\n", 610 | "\n", 611 | "```haskell\n", 612 | "longitud [1,2,3]\n", 613 | "1 + longitud [2,3]\n", 614 | "1 + (1 + longitud [3])\n", 615 | "1 + (1 + (1 + longitud []))\n", 616 | "1 + (1 + (1 + 0))\n", 617 | "1 + (1 + 1)\n", 618 | "1 + 2\n", 619 | "3\n", 620 | "```\n", 621 | "Esta función viene ya definida como `length` (aunque su tipo es más general ya que puede definirse también sobre otros tipos de estructuras que no sean listas):" 622 | ] 623 | }, 624 | { 625 | "cell_type": "code", 626 | "execution_count": null, 627 | "metadata": { 628 | "collapsed": false 629 | }, 630 | "outputs": [], 631 | "source": [ 632 | "longitud l1" 633 | ] 634 | }, 635 | { 636 | "cell_type": "markdown", 637 | "metadata": {}, 638 | "source": [ 639 | "La función `(!!) :: [a] -> Int -> a` nos permite acceder al elemento en . Es una función infija: cuando indicamos su tipo o la pasamos como argumento la escribimos entre paréntesis pero cuando la definimos o utilizamos la podemos poner de forma infija.\n", 640 | "\n", 641 | "La definimos aquí con 3 exclamaciones para no pisar la definición estandar:" 642 | ] 643 | }, 644 | { 645 | "cell_type": "code", 646 | "execution_count": null, 647 | "metadata": { 648 | "collapsed": true 649 | }, 650 | "outputs": [], 651 | "source": [ 652 | "(!!!) :: [a] -> Int -> a\n", 653 | "[] !!! _ = error \"Índice demasiado grande\"\n", 654 | "(x:_) !!! 0 = x\n", 655 | "(_:xs) !!! n = xs !!! (n-1)" 656 | ] 657 | }, 658 | { 659 | "cell_type": "code", 660 | "execution_count": null, 661 | "metadata": { 662 | "collapsed": false 663 | }, 664 | "outputs": [], 665 | "source": [ 666 | "[1,2,3] !!! 1" 667 | ] 668 | }, 669 | { 670 | "cell_type": "markdown", 671 | "metadata": {}, 672 | "source": [ 673 | "Para llamarla de forma prefija le ponemos paréntesis:" 674 | ] 675 | }, 676 | { 677 | "cell_type": "code", 678 | "execution_count": null, 679 | "metadata": { 680 | "collapsed": false 681 | }, 682 | "outputs": [], 683 | "source": [ 684 | "(!!!) [1,2,3] 0" 685 | ] 686 | }, 687 | { 688 | "cell_type": "markdown", 689 | "metadata": {}, 690 | "source": [ 691 | "_**Ejercicio**: Define la función `<>` que concatena dos listas_" 692 | ] 693 | }, 694 | { 695 | "cell_type": "code", 696 | "execution_count": null, 697 | "metadata": { 698 | "collapsed": true 699 | }, 700 | "outputs": [], 701 | "source": [ 702 | "concatena :: [a] -> [a] -> [a]\n", 703 | "-- Tu definición" 704 | ] 705 | }, 706 | { 707 | "cell_type": "code", 708 | "execution_count": null, 709 | "metadata": { 710 | "collapsed": false 711 | }, 712 | "outputs": [], 713 | "source": [ 714 | "[1,2] `concatena` [1,2] -- [1,2,1,2]" 715 | ] 716 | }, 717 | { 718 | "cell_type": "markdown", 719 | "metadata": {}, 720 | "source": [ 721 | "## Funciones de orden superior" 722 | ] 723 | }, 724 | { 725 | "cell_type": "markdown", 726 | "metadata": {}, 727 | "source": [ 728 | "Las listas son una parte fundamental de Haskell. Para trabajar con ellas suelen utilizarse **funciones de orden superior**: funciones que toman otras funciones como argumentos.\n", 729 | "\n", 730 | "Un primer ejemplo es la función `map :: (a -> b) -> [a] -> [b]`, que toma una función y nos devuelve su versión sobre listas:\n", 731 | "\n", 732 | "```\n", 733 | "map f [a1, a2, ..., an] = [f a1, f a2, ..., f an]\n", 734 | "```\n", 735 | "\n", 736 | "Su definición es la siguiente (escribimos `map'` para no redefinir la función que ya está incluida):" 737 | ] 738 | }, 739 | { 740 | "cell_type": "code", 741 | "execution_count": null, 742 | "metadata": { 743 | "collapsed": true 744 | }, 745 | "outputs": [], 746 | "source": [ 747 | "map' :: (a -> b) -> [a] -> [b]\n", 748 | "map' f [] = []\n", 749 | "map' f (x:xs) = f x : map' f xs" 750 | ] 751 | }, 752 | { 753 | "cell_type": "markdown", 754 | "metadata": {}, 755 | "source": [ 756 | "De esta forma y combinándolo con la aplicación parcial por la currificación podemos por ejemplo definir una función que tome una lista y sume 1 a todos sus elementos:" 757 | ] 758 | }, 759 | { 760 | "cell_type": "code", 761 | "execution_count": null, 762 | "metadata": { 763 | "collapsed": true 764 | }, 765 | "outputs": [], 766 | "source": [ 767 | "suma1 = map (+1)\n", 768 | "-- Equivalentemente: suma1 xs = map (+1) xs" 769 | ] 770 | }, 771 | { 772 | "cell_type": "code", 773 | "execution_count": null, 774 | "metadata": { 775 | "collapsed": false 776 | }, 777 | "outputs": [], 778 | "source": [ 779 | "suma1 [1,2,3]" 780 | ] 781 | }, 782 | { 783 | "cell_type": "markdown", 784 | "metadata": {}, 785 | "source": [ 786 | "_**Ejercicio**: Define una función que tome una lista de listas y tome sus `cabezas`. Indica su tipo:_" 787 | ] 788 | }, 789 | { 790 | "cell_type": "code", 791 | "execution_count": null, 792 | "metadata": { 793 | "collapsed": true 794 | }, 795 | "outputs": [], 796 | "source": [ 797 | "cabezas :: -- Indica su tipo\n", 798 | "cabezas = -- Su definición" 799 | ] 800 | }, 801 | { 802 | "cell_type": "markdown", 803 | "metadata": {}, 804 | "source": [ 805 | "Otra función útil y más general es la función `foldr`, que toma una operación binaria y un valor por defecto y aplica esa operación a los elementos de una lista:\n", 806 | "```haskell\n", 807 | "foldr (⊕) z [a1,...,an] = a1 ⊕ (a2 ⊕ (... ⊕ (an ⊕ z)))\n", 808 | "```\n", 809 | "\n", 810 | "`foldr` puede utilizarse para definir cualquier función que siga el siguiente esquema:\n", 811 | "\n", 812 | "```haskell\n", 813 | "f [] = z\n", 814 | "f (x:xs) = x ⊕ f xs\n", 815 | "```\n", 816 | "\n", 817 | "Un ejemplo común es la función `sum`, que suma los elementos de una lista y que podemos definir como:\n", 818 | "\n", 819 | "```haskell\n", 820 | "sum [] = 0\n", 821 | "sum (x:xs) = x + sum xs\n", 822 | "```\n", 823 | "\n", 824 | "Utilizando `foldr` su definición se reduce a `sum = foldr (+) 0`:" 825 | ] 826 | }, 827 | { 828 | "cell_type": "code", 829 | "execution_count": null, 830 | "metadata": { 831 | "collapsed": false 832 | }, 833 | "outputs": [], 834 | "source": [ 835 | "foldr (+) 0 [1,2,3]" 836 | ] 837 | }, 838 | { 839 | "cell_type": "markdown", 840 | "metadata": {}, 841 | "source": [ 842 | "Un caso útil de la función `foldr` es su aplicación a los [monoides](https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Monoid.html), reduciendo una lista de elementos del monoide a uno sólo mediante la aplicación de la operación del monoide.\n", 843 | "\n", 844 | "_**Ejercicio**: Aprovechando la estructura de monoide de las funciones sobre un tipo define la función `compose :: [a -> a] -> a -> a` que compone una lista de funciones en una sola_" 845 | ] 846 | }, 847 | { 848 | "cell_type": "code", 849 | "execution_count": null, 850 | "metadata": { 851 | "collapsed": true 852 | }, 853 | "outputs": [], 854 | "source": [ 855 | "compose :: [a -> a] -> a -> a\n", 856 | "compose = -- Tu definición" 857 | ] 858 | }, 859 | { 860 | "cell_type": "code", 861 | "execution_count": null, 862 | "metadata": { 863 | "collapsed": true 864 | }, 865 | "outputs": [], 866 | "source": [ 867 | "compose [(+1),(*2),(+3)] 0 -- (0 + 3)*2 + 1" 868 | ] 869 | }, 870 | { 871 | "cell_type": "markdown", 872 | "metadata": {}, 873 | "source": [ 874 | "_**Ejercicio**: Define las funciones `<>`, `length` y `map` a partir de `foldr`_" 875 | ] 876 | }, 877 | { 878 | "cell_type": "markdown", 879 | "metadata": {}, 880 | "source": [ 881 | "Un último ejemplo de función de orden superior es `filter`, que filtra una lista según un predicado:" 882 | ] 883 | }, 884 | { 885 | "cell_type": "code", 886 | "execution_count": null, 887 | "metadata": { 888 | "collapsed": true 889 | }, 890 | "outputs": [], 891 | "source": [ 892 | "filtro:: (a->Bool) -> [a] -> [a]\n", 893 | "filtro f [] = []\n", 894 | "filtro f (x:xs) = if f x then x:(filtro f xs) else filtro f xs" 895 | ] 896 | }, 897 | { 898 | "cell_type": "code", 899 | "execution_count": null, 900 | "metadata": { 901 | "collapsed": false 902 | }, 903 | "outputs": [], 904 | "source": [ 905 | "filtro (>0) [1,-2,3]" 906 | ] 907 | }, 908 | { 909 | "cell_type": "markdown", 910 | "metadata": {}, 911 | "source": [ 912 | "## Definición de tipos " 913 | ] 914 | }, 915 | { 916 | "cell_type": "markdown", 917 | "metadata": {}, 918 | "source": [ 919 | "Para definir un tipo se utiliza la palabra clave `data` y se definen distintos **constructores de datos** que empiezan por mayúscula y están separados por `|`. Estas funciones nos permiten crear instancias de ese tipo. Por ejemplo, el tipo `Bool` está definido:\n", 920 | "\n", 921 | "```haskell\n", 922 | "data Bool = False | True\n", 923 | "```\n", 924 | "\n", 925 | "De forma equivalente el tipo `Int` podría definirse listando todos los números (aunque en este caso la definición es primitiva):\n", 926 | "```haskell\n", 927 | "data Int = -9223372036854775808|...|-1|0|1|...|9223372036854775807\n", 928 | "```\n", 929 | "\n", 930 | "Cuando listamos los posibles casos de una función sólo podemos utilizar los constructores de datos para ello. Como primer ejemplo definimos un tipo `Forma` con 3 posibles instancias: triángulos,cuadrados y círculos y damos una función que nos indica si una forma es un polígono:" 931 | ] 932 | }, 933 | { 934 | "cell_type": "code", 935 | "execution_count": null, 936 | "metadata": { 937 | "collapsed": true 938 | }, 939 | "outputs": [], 940 | "source": [ 941 | "data Forma = Triangulo | Cuadrado | Circulo -- :t Triangulo ?\n", 942 | "\n", 943 | "esPoligono :: Forma -> Bool\n", 944 | "esPoligono Triangulo = True\n", 945 | "esPoligono Cuadrado = True\n", 946 | "esPoligono Circulo = False" 947 | ] 948 | }, 949 | { 950 | "cell_type": "markdown", 951 | "metadata": {}, 952 | "source": [ 953 | "Los constructores de datos también pueden tomar argumentos, en cuyo caso indicamos el tipo de los mismos. `deriving Show` nos permite mostrar instancias de un tipo como cadenas de caracteres.\n", 954 | "\n", 955 | "Definimos también una función que nos da la edad de una persona y otra que nos indica si dos personas tienen la misma edad:" 956 | ] 957 | }, 958 | { 959 | "cell_type": "code", 960 | "execution_count": null, 961 | "metadata": { 962 | "collapsed": true 963 | }, 964 | "outputs": [], 965 | "source": [ 966 | "data Persona = P String Int deriving Show -- :t P ?\n", 967 | "\n", 968 | "-- Obtener la edad de una persona\n", 969 | "getEdad :: Persona -> Int\n", 970 | "getEdad (P nombre edad) = edad\n", 971 | "\n", 972 | "-- Tienen la misma edad?\n", 973 | "mismaEdad :: Persona -> Persona -> Bool\n", 974 | "mismaEdad (P _ e1) (P _ e2) = e1 == e2" 975 | ] 976 | }, 977 | { 978 | "cell_type": "code", 979 | "execution_count": null, 980 | "metadata": { 981 | "collapsed": false 982 | }, 983 | "outputs": [], 984 | "source": [ 985 | "P \"Pedro\" 47" 986 | ] 987 | }, 988 | { 989 | "cell_type": "markdown", 990 | "metadata": {}, 991 | "source": [ 992 | "En general un tipo puede tener un número arbitrario de constructores de datos con cualquier número de argumentos.\n", 993 | "\n", 994 | "Podemos definir los tipos de forma recursiva: un ejemplo clásico son los naturales definidos como en la aritmética de Peano: un natural puede ser el cero (`Z :: Nat`) o el sucesor de otro natural (`S :: Nat -> Nat` es la función sucesor).\n", 995 | "\n", 996 | "Definimos también la suma de naturales y una función que transforma naturales a enteros, así como el valor `infinito`:" 997 | ] 998 | }, 999 | { 1000 | "cell_type": "code", 1001 | "execution_count": null, 1002 | "metadata": { 1003 | "collapsed": true 1004 | }, 1005 | "outputs": [], 1006 | "source": [ 1007 | "-- Tipos recursivos\n", 1008 | "data Nat = Z | S Nat -- Naturales (Peano)\n", 1009 | "\n", 1010 | "suma :: Nat -> Nat -> Nat\n", 1011 | "-- suma de naturales\n", 1012 | "suma Z n = n\n", 1013 | "suma (S n) m = S (suma n m)\n", 1014 | "\n", 1015 | "toInt :: Nat -> Int\n", 1016 | "-- Pasar a entero\n", 1017 | "toInt Z = 0\n", 1018 | "toInt (S n) = 1 + toInt n\n", 1019 | "\n", 1020 | "infinito = S infinito" 1021 | ] 1022 | }, 1023 | { 1024 | "cell_type": "code", 1025 | "execution_count": null, 1026 | "metadata": { 1027 | "collapsed": false 1028 | }, 1029 | "outputs": [], 1030 | "source": [ 1031 | "toInt (S (S Z))" 1032 | ] 1033 | }, 1034 | { 1035 | "cell_type": "markdown", 1036 | "metadata": {}, 1037 | "source": [ 1038 | "_**Ejercicio**: Define mediante recursión mutua dos predicados que indiquen si un natural es `par` o `impar`_" 1039 | ] 1040 | }, 1041 | { 1042 | "cell_type": "markdown", 1043 | "metadata": {}, 1044 | "source": [ 1045 | "### Constructores de tipos" 1046 | ] 1047 | }, 1048 | { 1049 | "cell_type": "markdown", 1050 | "metadata": {}, 1051 | "source": [ 1052 | "Los **constructores de tipos** son funciones sobre tipos: toman uno o más tipos y devuelven un nuevo tipo. Ya hemos visto un caso concreto: el constructor de tipos lista `[]` que se definiría:\n", 1053 | "\n", 1054 | "```haskell\n", 1055 | "data [a] = [] | a:[a] -- Sintaxis no legal\n", 1056 | "```\n", 1057 | "\n", 1058 | "Es decir: una lista de tipo `a` puede ser la lista vacía o un elemento de tipo `a` antepuesto a una lista de tipo `a`. Otro ejemplo es el constructor de tipos `Either`, que nos permite crear un tipo que [*suma* otros dos](http://tux.ugr.es/dgiim/blog/2015/03/24/algebra-tipos):\n", 1059 | "\n", 1060 | "```haskell\n", 1061 | "data Either a b = Left a | Right b\n", 1062 | "```\n", 1063 | "\n", 1064 | "Como ejemplo final de esta sección definimos los árboles binarios de tipo `a` y una función que devuelve el reflejado de un árbol:" 1065 | ] 1066 | }, 1067 | { 1068 | "cell_type": "code", 1069 | "execution_count": null, 1070 | "metadata": { 1071 | "collapsed": true 1072 | }, 1073 | "outputs": [], 1074 | "source": [ 1075 | "data Tree a = Empty | Node a (Tree a) (Tree a)\n", 1076 | "\n", 1077 | "-- Árbol reflejado\n", 1078 | "refl :: Tree a -> Tree a\n", 1079 | "refl Empty = Empty\n", 1080 | "refl (Node a t1 t2) = Node a (refl t2) (refl t1)\n" 1081 | ] 1082 | }, 1083 | { 1084 | "cell_type": "markdown", 1085 | "metadata": {}, 1086 | "source": [ 1087 | "_**Ejercicio**: Define una función que devuelva la `altura :: Tree a -> Int` de un árbol_" 1088 | ] 1089 | }, 1090 | { 1091 | "cell_type": "markdown", 1092 | "metadata": {}, 1093 | "source": [ 1094 | "## Clases de tipos" 1095 | ] 1096 | }, 1097 | { 1098 | "cell_type": "markdown", 1099 | "metadata": {}, 1100 | "source": [ 1101 | "Algunos tipos tienen propiedades comunes. Para aprovecharlas\n", 1102 | "se definen **clases de tipos**, que agrupan tipos con la misma interfaz. La mayoría de los tipos son instancias de `Eq`, porque disponen de una función `(==)` que comprueba la igualdad. Las instancias de la clase `Num` pueden sumarse y multiplicarse, las de `Show` pueden convertirse a una `String` y las de `Ord` pueden ordenarse. \n", 1103 | "\n", 1104 | "Una clase de tipos se define a partir de las funciones que pueden utilizar de forma común los tipos que pertenecen a la misma. Por ejemplo, `Eq` se define:\n", 1105 | "\n", 1106 | "```haskell\n", 1107 | "class Eq a where\n", 1108 | " (==) :: a -> a -> Bool\n", 1109 | " (/=) :: a -> a -> Bool\n", 1110 | " -- Sólo hace falta definir uno, el otro por defecto:\n", 1111 | " x /= y = not (x == y)\n", 1112 | " x == y = not (x /= y)\n", 1113 | "```\n", 1114 | "\n", 1115 | "Como ejemplo declaramos como instancia de la clase `Eq` al tipo de los naturales `Nat`:" 1116 | ] 1117 | }, 1118 | { 1119 | "cell_type": "code", 1120 | "execution_count": null, 1121 | "metadata": { 1122 | "collapsed": true 1123 | }, 1124 | "outputs": [], 1125 | "source": [ 1126 | "instance Eq Nat where\n", 1127 | " Z == Z = True\n", 1128 | " S n == S m = n == m\n", 1129 | " _ == _ = False" 1130 | ] 1131 | }, 1132 | { 1133 | "cell_type": "code", 1134 | "execution_count": null, 1135 | "metadata": { 1136 | "collapsed": false 1137 | }, 1138 | "outputs": [], 1139 | "source": [ 1140 | "S Z == infinito" 1141 | ] 1142 | }, 1143 | { 1144 | "cell_type": "markdown", 1145 | "metadata": {}, 1146 | "source": [ 1147 | "Otro ejemplo serían los árboles, pero en estos debemos imponer la restricción de que el tipo de sus elementos sea comparable por igualdad:" 1148 | ] 1149 | }, 1150 | { 1151 | "cell_type": "code", 1152 | "execution_count": null, 1153 | "metadata": { 1154 | "collapsed": false 1155 | }, 1156 | "outputs": [], 1157 | "source": [ 1158 | "instance (Eq a) => Eq (Tree a) where\n", 1159 | " Empty == Empty = True\n", 1160 | " Node a t1 t2 == Node a' t1' t2' = a == a' \n", 1161 | " && t1 == t1' && t2 == t2'" 1162 | ] 1163 | }, 1164 | { 1165 | "cell_type": "markdown", 1166 | "metadata": {}, 1167 | "source": [ 1168 | "Cuando una función toma tipos que deben ser de una cierta clase se indica en su declaración de tipo con `=>`. Por ejemplo la función `elem` nos indica si un valor es elemento de una lista:\n", 1169 | "\n", 1170 | "```haskell\n", 1171 | "elem :: (Eq a) => a -> [a] -> Bool\n", 1172 | "x `elem` [] = False\n", 1173 | "x `elem` (y:ys) = x == y || x `elem` ys\n", 1174 | "```" 1175 | ] 1176 | }, 1177 | { 1178 | "cell_type": "code", 1179 | "execution_count": null, 1180 | "metadata": { 1181 | "collapsed": false 1182 | }, 1183 | "outputs": [], 1184 | "source": [ 1185 | "1 `elem` [2,3,4]" 1186 | ] 1187 | }, 1188 | { 1189 | "cell_type": "markdown", 1190 | "metadata": {}, 1191 | "source": [ 1192 | "## Functores" 1193 | ] 1194 | }, 1195 | { 1196 | "cell_type": "markdown", 1197 | "metadata": {}, 1198 | "source": [ 1199 | "Por último definimos una clase de tipos sobre constructores de tipos de uso habitual: los functores.\n", 1200 | "\n", 1201 | "Un functor `f` es un contenedor o un contexto computacional sobre el que podemos definir una función `fmap :: (Functor f) => (a -> b) -> f a -> f b` que aplique una función `a -> b` sobre todos los elementos de una estructura `f a` para devolver otra `f b`.\n", 1202 | "\n", 1203 | "Un ejemplo de functores serían las listas, para las que `fmap` es la función `map`." 1204 | ] 1205 | }, 1206 | { 1207 | "cell_type": "code", 1208 | "execution_count": null, 1209 | "metadata": { 1210 | "collapsed": false 1211 | }, 1212 | "outputs": [], 1213 | "source": [ 1214 | "fmap (<>\"!\") [\"Azúcar\", \"Especias\", \"Cosas bonitas\"]" 1215 | ] 1216 | }, 1217 | { 1218 | "cell_type": "markdown", 1219 | "metadata": {}, 1220 | "source": [ 1221 | "Toda instancia de la clase `Functor` debe cumplir las siguiente **leyes**:\n", 1222 | "\n", 1223 | "```haskell\n", 1224 | "fmap id == id\n", 1225 | "fmap f . fmap g == fmap (f . g)\n", 1226 | "```\n", 1227 | "\n", 1228 | "Estas leyes vienen de la [teoría de categorías](https://en.wikipedia.org/wiki/Functor) y permiten realizar toda clase de optimizaciones al código escrito con functores.\n", 1229 | "\n", 1230 | "Como último ejemplo definimos `Tree` como instancia de los functores:" 1231 | ] 1232 | }, 1233 | { 1234 | "cell_type": "code", 1235 | "execution_count": null, 1236 | "metadata": { 1237 | "collapsed": true 1238 | }, 1239 | "outputs": [], 1240 | "source": [ 1241 | "instance Functor Tree where\n", 1242 | " fmap f Empty = Empty\n", 1243 | " fmap f (Node a t1 t2) = Node (f a) (fmap f t1) (fmap f t2)" 1244 | ] 1245 | }, 1246 | { 1247 | "cell_type": "markdown", 1248 | "metadata": {}, 1249 | "source": [ 1250 | "# Para saber más" 1251 | ] 1252 | }, 1253 | { 1254 | "cell_type": "markdown", 1255 | "metadata": {}, 1256 | "source": [ 1257 | "Si quieres **aprender más** puedes echar un vistazo a los recursos disponibles en [libreim/haskell](https://github.com/libreim/haskell#haskell)." 1258 | ] 1259 | } 1260 | ], 1261 | "metadata": { 1262 | "kernelspec": { 1263 | "display_name": "Haskell", 1264 | "language": "haskell", 1265 | "name": "haskell" 1266 | }, 1267 | "language_info": { 1268 | "codemirror_mode": "ihaskell", 1269 | "file_extension": ".hs", 1270 | "name": "haskell", 1271 | "version": "7.10.2" 1272 | } 1273 | }, 1274 | "nbformat": 4, 1275 | "nbformat_minor": 0 1276 | } 1277 | -------------------------------------------------------------------------------- /PrimeraParte/wcount/mimi.hs: -------------------------------------------------------------------------------- 1 | import Control.Monad (forever) 2 | 3 | mimi :: String -> String 4 | mimi = map mimiChar 5 | where mimiChar x = 6 | if x `elem` "aeiou" then 'i' 7 | else if x `elem` "áéíóú" then 'í' 8 | else x 9 | 10 | main = forever (interact mimi) 11 | -------------------------------------------------------------------------------- /PrimeraParte/wcount/sort.hs: -------------------------------------------------------------------------------- 1 | import Data.List (partition) 2 | import Control.Monad (forever, void) 3 | 4 | qsort :: Ord a => [a] -> [a] 5 | qsort [] = [] 6 | qsort (x:xs) = qsort lower <> [x] <> qsort higher 7 | where (lower, higher) = partition (>= print . qsort) 10 | -------------------------------------------------------------------------------- /PrimeraParte/wcount/wcount.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | int main(){ 10 | unordered_map counter; 11 | wstring word; 12 | 13 | ios_base::sync_with_stdio(false); 14 | wcin.imbue(locale("en_US.UTF-8")); 15 | wcout.imbue(locale("en_US.UTF-8")); 16 | 17 | while (wcin >> word){ 18 | word.erase(remove_if(word.begin(), word.end(), ::iswpunct), word.end()); 19 | transform(word.begin(), word.end(), word.begin(), ::towlower); 20 | 21 | if(word.length() == 0) 22 | continue; 23 | 24 | auto it = counter.find(word); 25 | if(it != counter.end()) 26 | it->second += 1; 27 | else 28 | counter.emplace(word, 1); 29 | } 30 | 31 | const int MAX = 200; 32 | int n = 0, maxLen = 0; 33 | 34 | vector> words; 35 | for(auto itr : counter) 36 | words.push_back(itr); 37 | 38 | sort(words.begin(), words.end(), 39 | [=](auto a, auto b){ 40 | return a.second > b.second; 41 | }); 42 | 43 | n = 0; 44 | for(const auto it : words) { 45 | if(++n > MAX) 46 | break; 47 | if(it.first.length() > maxLen) 48 | maxLen = it.first.length(); 49 | } 50 | 51 | n = 0; 52 | for (const auto it : words) { 53 | if(++n > MAX) 54 | break; 55 | wcout << setw(maxLen) << it.first << ": " << it.second << endl; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /PrimeraParte/wcount/wcount.hs: -------------------------------------------------------------------------------- 1 | import qualified Data.Text.Lazy.IO as T 2 | import qualified Data.Text.Lazy as T 3 | import qualified Data.Map.Strict as M 4 | import Data.List 5 | import Text.Printf 6 | import Data.Char 7 | 8 | toWords = T.words . T.filter (not . isPunctuation) . T.map toLower 9 | 10 | countWords = foldl' addWord mempty 11 | where addWord counter word = M.insertWith (+) word 1 counter 12 | 13 | showMap :: M.Map T.Text Int -> IO () 14 | showMap hm = putStrLn $ concat $ map showPair selected 15 | where selected = take 200 $ sortOn (negate . snd) $ M.toList hm 16 | maxLen = maximum (map (T.length . fst) selected) 17 | showPair (k,v) = printf ("%" <> show maxLen <> "s: %d\n") k v 18 | 19 | main = T.getContents >>= showMap . countWords . toWords 20 | -------------------------------------------------------------------------------- /PrimeraParte/wcount/wcount.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | import fileinput 3 | import re 4 | 5 | def main(): 6 | counter = Counter() 7 | 8 | for line in fileinput.input(): 9 | filtered = re.sub("[,\.!?;,:\-\"']", '', line.rstrip()) 10 | words = filtered.split() 11 | for word in words: 12 | counter[word.lower()] += 1 13 | 14 | sw = list(enumerate(sorted(counter.items(), key=lambda p: -p[1]))) 15 | 16 | max_len = 0 17 | for i, (word, freq) in sw: 18 | if i > 200: 19 | break 20 | elif len(word) > max_len: 21 | max_len = len(word) 22 | 23 | for i, (word, freq) in sw: 24 | if i > 200: 25 | break 26 | else: 27 | print(("{:>" + str(max_len) + "}: {}").format(word, freq)) 28 | 29 | 30 | if __name__ == "__main__": 31 | main() 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # haskell 2 | 3 | Repositorio de recursos de libreim sobre Haskell. 4 | 5 | ## Cuaderno en IHaskell 6 | 7 | [Introducción a Haskell interactiva](https://github.com/libreim/haskell/blob/master/PrimeraParte/PrimeraParte.ipynb) que describe desde cero el sistema de tipos, cómo definir y utilizar funciones, tipos y constructores de tipos y funtores. Una versión actualizada del código original utilizado en la charla está disponible [aquí](https://github.com/libreim/haskell/tree/master/PrimeraParte). 8 | 9 | Contiene ejercicios sobre los temas introducidos que pueden realizarse en el mismo cuaderno si **se ejecuta con [IHaskell](https://github.com/gibiansky/IHaskell)**. 10 | 11 | También se incluyen [algunos ejercicios](https://github.com/libreim/haskell/blob/master/ejercicios.md) adicionales. 12 | 13 | 14 | ## Introducción a Haskell 15 | 16 | Los primeros apuntes que creamos están revisados y [disponibles en pdf](https://github.com/libreim/haskell/blob/master/apuntes/introHaskell.pdf). Son una introducción corta que describe desde cero el sistema de tipos, los constructores de tipos más habituales (listas y tuplas) y cómo definir y utilizar funciones y tipos. 17 | 18 | También está disponible [el código fuente](https://github.com/libreim/haskell/tree/master/apuntes) en LaTeX. 19 | 20 | ## Funtores y Mónadas 21 | 22 | Ejemplos autocontenidos de funtores y uso de mónadas. Requieren los conocimientos de las introducciones desde cero. 23 | 24 | * [Funtores](https://github.com/libreim/haskell/blob/master/SegundaParte/1.funtores.hs) 25 | * [Manejo de errores con `Maybe`](https://github.com/libreim/haskell/blob/master/SegundaParte/2.errores.hs) 26 | * [Distribuciones de probabilidad con `State`](https://github.com/libreim/haskell/blob/master/SegundaParte/3.distribuciones.hs) 27 | * [Ejemplo de parser con `Parsec`](https://github.com/libreim/haskell/blob/master/SegundaParte/4.parsers.hs) 28 | 29 | ## Haskell en la OSL 30 | 31 | Como parte de una reunión de usuarios de Github en Granada dimos una charla en la [OSL](http://osl.ugr.es). Incluimos aquí [la presentación con notas](https://github.com/libreim/haskell/blob/master/CharlaOSL.pdf). 32 | 33 | ### Ejemplos en Haskell literario 34 | 35 | Ejemplos autocontenidos realizados en [Haskell literario](https://wiki.haskell.org/Literate_programming). Pueden compilarse a pdf o ejecutarse con ghc mediante el Makefile que incluimos. Requieren conocer los contenidos descritos en las introducciones desde cero: 36 | 37 | * [Quicksort](https://github.com/libreim/haskell/blob/master/Haskell%20Literario/quicksort.lhs) 38 | * [Árboles binarios](https://github.com/libreim/haskell/blob/master/Haskell%20Literario/bintree.lhs) 39 | * [Sucesión de Fibonacci](https://github.com/libreim/haskell/blob/master/Haskell%20Literario/fibonacci.lhs) 40 | * [Monoides](https://github.com/libreim/haskell/blob/master/Haskell%20Literario/monoides.lhs) 41 | * [La categoría Hask](https://github.com/libreim/haskell/blob/master/Haskell%20Literario/hask.lhs) 42 | 43 | ## Posts 44 | 45 | En el [blog](https://libreim.github.io/blog/) de libreim hay disponibles varios posts que expanden distintos temas de Haskell, relacionados con la teoría de tipos y la teoría de categorías: 46 | 47 | - [Teoría de tipos](https://libreim.github.io/blog/2016/01/08/teoria-de-tipos/) una lista de lectura sobre teoría de tipos. Incluye: 48 | - [Álgebra de tipos](https://libreim.github.io/blog/2015/03/24/algebra-tipos). Construcción de un álgebra sobre los tipos de Haskell 49 | - [Inducción estructural](https://libreim.github.io/blog/2015/03/14/induccion-estructural/). Generalización de la inducción para trabajar sobre tipos 50 | - [Isomorfismo de Curry-Howard](https://libreim.github.io/blog/2014/12/04/curry-howard/). Exposición del isomorfismo de Curry-Howard en Haskell y su utilización en Coq 51 | - [Mónadas](https://libreim.github.io/blog/2016/12/21/monadas/). Motivación de las mónadas y visión categórica. Esta última parte requiere conocer conceptos de [teoría de categorías](https://libreim.github.io/blog/2014/10/04/intro-categorias). 52 | 53 | - Más recursos en nuestra [página de recursos](https://libreim.github.io/recursos/) 54 | -------------------------------------------------------------------------------- /SegundaParte/1.funtores.hs: -------------------------------------------------------------------------------- 1 | import Data.List 2 | 3 | -- ¡En Haskell, se pueden tratar listas infinitas! 4 | -- Eso es gracias a la evaluación perezosa 5 | naturals :: [Integer] 6 | naturals = [1..] 7 | 8 | -- Pero no es lo único que se puede hacer con las listas. 9 | -- Podemos mapear sobre ellas. Un contenedor sobre el que se 10 | -- puede mapear forma una estructura algebraica que se llama 11 | -- funtor. 12 | -- 13 | -- >>> map (*2) it 14 | -- [2,4,6,8,10,12,14,16,18,20] 15 | -- >>> map toLower "HOLA!" 16 | -- "hola!" 17 | -- 18 | -- Aquí calculamos los números pares, con una función con 19 | -- aplicación parcial 20 | evenlist :: [Integer] 21 | evenlist = map (*2) naturals 22 | 23 | -- Y aquí los impares, con una función lambda 24 | oddlist :: [Integer] 25 | oddlist = map (\n -> 2*n - 1) naturals 26 | 27 | -- Como una generalización de map, existe 'fmap', que no sólo 28 | -- funciona sobre listas. Podemos mapear sobre Maybe o sobre pares, 29 | -- o incluso sobre IO, por ejemplo: 30 | pair20 :: (Int,Int) 31 | pair20 = fmap (+2) (2,4) 32 | 33 | just3 :: Maybe Int 34 | just3 = Just 3 35 | 36 | just6 :: Maybe Int 37 | just6 = fmap (*2) just3 38 | 39 | getInt :: IO Int 40 | getInt = fmap read getLine 41 | 42 | getPowerOf2 :: IO Int 43 | getPowerOf2 = fmap (2^) getInt 44 | 45 | -- Además, <$> es un equivalente de fmap que es útil para escribirlo 46 | -- como operador infijo. 47 | getWords :: IO [String] 48 | getWords = words <$> getLine 49 | 50 | 51 | 52 | -- Podemos convertir a nuestros árboles binarios en funtores y usarlos 53 | -- con las funciones desde fmap 54 | data Tree a = Node a (Tree a) (Tree a) | Nil 55 | deriving (Show) 56 | 57 | instance Functor Tree where 58 | fmap f Nil = Nil 59 | fmap f (Node x l r) = Node (f x) (fmap f l) (fmap f r) 60 | 61 | aTree :: Tree Int 62 | aTree = Node 1 (Node 3 (Node 2 Nil Nil) Nil) (Node 4 (Node 5 Nil Nil) (Node 6 Nil Nil)) 63 | -------------------------------------------------------------------------------- /SegundaParte/2.errores.hs: -------------------------------------------------------------------------------- 1 | {- 2 | Intentamos obtener raíces cuadradas en los reales usando el método de Newton. 3 | Y parar cuando estemos suficientemente cerca (más cerca que un ε dado). 4 | -} 5 | 6 | -- Aquí imprimiremos los números en coma flotante con sólo dos decimales. 7 | -- Nada importante, sólo detalles para hacer que el resto se vea bonito. 8 | -- Incluimos además una función división que toma enteros y devuelve flotantes. 9 | import Control.Monad 10 | import Text.Printf 11 | printd :: Double -> IO () 12 | printd = printf "%.3f" 13 | 14 | (//) :: Int -> Int -> Double 15 | (//) a b = (fromIntegral a) / (fromIntegral b) 16 | 17 | 18 | -- Implementamos el concepto de límite en una lista infinita buscando hasta 19 | -- encontrar dos términos que se diferencien en menos distancia que épsilon. 20 | -- 21 | -- >>> armonic = map (1 //) [1..] 22 | -- >>> printd $ limit 0.0000000001 armonic 23 | -- 0.000 24 | -- 25 | -- >>> powerseq = map ((1//) . (2^)) [1..] 26 | -- >>> powerseries = scanl (+) 0 powerseq 27 | -- >>> printd $ limit 0.000000001 powerseries 28 | -- 1.000 29 | limit :: Double -> [Double] -> Double 30 | limit epsilon (x:y:xs) 31 | | abs (x-y) < epsilon = y 32 | | otherwise = limit epsilon (y:xs) 33 | 34 | newtonaprox :: Double -> Double -> Double 35 | newtonaprox n x = (x + n/x)/2 36 | 37 | sqroot :: Double -> Double 38 | sqroot 0 = 0 39 | sqroot x = limit 0.003 (iterate (newtonaprox x) x) 40 | 41 | 42 | 43 | -- Usamos la función para resolver una ecuación de segundo grado. 44 | -- Podemos definir una estructura de datos `QPol` para el polinomio y una 45 | -- función que lo resuelva obteniendo sus dos raíces: 46 | data QPol = QPol Double Double Double 47 | instance Show QPol where 48 | show (QPol a b c) = printf "%fx² + %fx + %f" a b c 49 | 50 | solve :: QPol -> (Double,Double) 51 | solve (QPol a b c) = (sol1,sol2) 52 | where sol1 = ( (-b) + sqroot(b*b-4*c*a) )/(2*a) 53 | sol2 = ( (-b) - sqroot(b*b-4*c*a) )/(2*a) 54 | 55 | 56 | -- Y podemos comprobar que funciona como esperamos: 57 | -- 58 | -- >>> pol = QPol 1 (-5) 6 59 | -- >>> putStrLn $ "Las soluciones de " <> show pol <> " son " <> solve pol 60 | -- Las soluciones de 1.0x² + -5.0x + 6.0 son (3.0,2.0) 61 | -- 62 | -- ¡Excepto en los casos en los que el discriminante es no positivo! 63 | -- El método está dando convergencia sólo cuando tratamos de sacar 64 | -- la raíz cuadrada de un número que es positivo, pero no funciona 65 | -- cuando sacamos la raíz de un número que no es positivo. 66 | -- 67 | -- La primera solución es hacer que devuelva Maybe en el caso de error. 68 | sqroot' :: Double -> Maybe Double 69 | sqroot' x 70 | | x < 0 = Nothing 71 | | x == 0 = Just 0.0 72 | | otherwise = Just ( limit 0.003 (iterate (newtonaprox x) x) ) 73 | 74 | 75 | 76 | -- Esto lo soluciona, pero nos crea un problema mayor. La función `solve` 77 | -- está usando la raíz cuadrada y se espera de ella que devuelva un número, 78 | -- no un posible error. 79 | -- 80 | -- Tenemos varias soluciones: 81 | -- Solución 1. Implementar una suma especial. 82 | (.+.) :: Maybe Float -> Maybe Float -> Maybe Float 83 | (.+.) Nothing _ = Nothing 84 | (.+.) _ Nothing = Nothing 85 | (.+.) (Just a) (Just b) = Just (a + b) 86 | 87 | -- Solución 2. Implementar una función especial sobre las habituales. 88 | -- El resto de funciones se implementan desde ella. 89 | errorAware :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c 90 | errorAware op Nothing _ = Nothing 91 | errorAware op _ Nothing = Nothing 92 | errorAware op (Just a) (Just b) = Just (op a b) 93 | 94 | (+.), (*.) :: Maybe Double -> Maybe Double -> Maybe Double 95 | (+.) = errorAware (+) 96 | (*.) = errorAware (*) 97 | 98 | -- Solución 3. ¡Usar mónadas! 99 | -- Las mónadas son una estructura algebraica que modela la composición 100 | -- de funciones que devuelven un contexto alrededor del valor o que 101 | -- comparten un cierto estado común. 102 | -- Cualquier contenedor (Maybe a, [a],...) puede ser una mónada si tiene 103 | -- un método que permita ese tipo de composición. 104 | -- 105 | -- Maybe es una mónada y list es una mónada 106 | {- 107 | 108 | class Monad m where 109 | (>>=) :: m a -> (a -> m b) -> m b 110 | return :: a -> m a 111 | 112 | -- Return de la mónada Maybe 113 | return x = Just x 114 | 115 | -- Bind de la mónada Maybe 116 | (Just x) >>= k = k x 117 | Nothing >>= _ = Nothing 118 | 119 | -- Return de la mónada List 120 | return x = [x] 121 | 122 | -- Bind de la mónada List 123 | xs >>= f = [y | x <- xs, y <- f x] 124 | 125 | -} 126 | -- Entonces las mónadas nos dan una forma de componer funciones con estado 127 | -- y de paso nos regalan multitud de funciones ya implementadas. 128 | {- 129 | 130 | sqroot' (sqroot' 3) -- ¡Error de tipos! 131 | sqroot' 3 >>= sqroot' -- Usando mónadas 132 | Just 3 >>= sqroot' >>= sqroot' -- Usando Just 133 | return 3 >>= sqroot' >>= sqroot' -- Equivalente a lo anterior 134 | 135 | -} 136 | -- La solución para implementar solve de nuevo es: 137 | solve'' :: QPol -> Maybe (Double,Double) 138 | solve'' (QPol a b c) = sqroot' (b*b-4*c*a) >>= (\d -> return (sol1 d, sol2 d)) 139 | where 140 | sol1 d = ( (-b) + d )/(2*a) 141 | sol2 d = ( (-b) - d )/(2*a) 142 | 143 | 144 | -- Esto funciona muy bien pero es difícil de escribir, porque tenemos 145 | -- que pasar el discriminante como argumento a una función lambda que 146 | -- nos calcula los dos usos del discriminante. 147 | -- Las mónadas nos dan una notación do, que es más fácil de usar para 148 | -- estos casos: 149 | solve2 :: QPol -> Maybe (Double,Double) 150 | solve2 (QPol a b c) = do 151 | -- Esta es una forma de escribir la composición de sqroot y el return 152 | -- Aquí guardamos el resultado de la primera función para usarlo luego 153 | discr <- sqroot' (b*b - 4*c*a) 154 | 155 | -- Aquí componemos con la segunda función, que ya usa el resultado 156 | -- de la primera función. 157 | return (((-b) + discr)/(2*a), ((-b) - discr)/(2*a)) 158 | 159 | -- Más claramente 160 | solve3 :: QPol -> Maybe (Double,Double) 161 | solve3 (QPol a b c) = do 162 | discr <- sqroot' (b*b - 4*c*a) 163 | return (((-b) + discr)/(2*a), ((-b) - discr)/(2*a)) 164 | 165 | 166 | -- Nótese que esta es una composición que tiene en cuenta la estructura 167 | -- de la mónada. Si la primera sqroot produce un error, esta se propaga 168 | -- por composición a todas las funciones. 169 | 170 | 171 | -- Otro ejemplo final, vamos a calcular una función como: 172 | -- f(x) = sqrt(sqrt(x)) + sqrt(x) + x 173 | -- Para eso vamos a usar 'return' para incluir x en la mónada 174 | -- y vamos a usar 'liftM2' para que (+) trabaje en la mónada. 175 | (+:) :: Maybe Double -> Maybe Double -> Maybe Double 176 | (+:) = liftM2 (+) 177 | 178 | f :: Double -> Maybe Double 179 | f x = (sqroot' x >>= sqroot') +: (sqroot' x) +: (return x) 180 | 181 | 182 | -- Leyes de las mónadas. 183 | -- En haskell no es necesario, pero cuando definimos una mónada, 184 | -- es una buena idea obligarla a que cumpla determinadas proposiciones 185 | -- relacionadas con el hecho de que debe comportarse como una buena 186 | -- composición. 187 | {- 188 | return a >>= f === f a 189 | m >>= return === m 190 | (m >>= f) >>= g === m >>= (\x -> f x >>= g) 191 | -} 192 | -------------------------------------------------------------------------------- /SegundaParte/3.distribuciones.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleInstances #-} 2 | {-# LANGUAGE TypeSynonymInstances #-} 3 | {- 4 | En este archivo vamos a usar mónadas para definir distribuciones 5 | discretas de probabilidad y aplicar operaciones algebraicas sobre ellas. 6 | -} 7 | import Control.Monad.State 8 | 9 | -- Generación aleatoria 10 | -- Para generar números pseudoaleatorios usaremos LCGs. La idea es tener 11 | -- un dado que nos dé una distribución de probabilidad uniforme dada una 12 | -- semilla y nos devuelva el resultado de la tirada y una nueva semilla 13 | -- aleatoria. Buscamos que un dado de seis caras sea, por ejemplo: 14 | -- 15 | -- dice 6 :: Seed -> (Int, Seed) 16 | -- 17 | -- Si quisiéramos tirar dos dados, tendríamos que tomar la semilla resultante 18 | -- del primer lanzamiento y pasarla al segundo; algo así: 19 | -- 20 | -- let (a,newseed) = dice 6 seed 21 | -- let (b,_) = dice 6 newseed 22 | -- print [a,b] 23 | -- 24 | -- Pero esto se hace demasiado complejo. La semilla, en el fondo, es un 25 | -- estado, así que podemos modelarla con la mónada State. Cada lanzamiento 26 | -- será de la forma: 27 | -- 28 | -- State Seed a === Seed -> (a, Seed) 29 | -- 30 | -- Luego podemos llamar a la distribución: Distribution a = State Seed a, y 31 | -- trabajar con ella usando las funciones normales de mónadas. 32 | type Seed = Int 33 | type Distribution = State Seed 34 | 35 | 36 | 37 | 38 | -- Nuestra primera distribución es un dado de "n" lados que usa internamente un 39 | -- generador de números aleatorios. 40 | dice :: Int -> Distribution Int 41 | dice n = state (\s -> (s `mod` n + 1, 16807*s `mod` 2147483647)) 42 | 43 | -- Una moneda es un dado de dos caras 44 | coin :: Distribution Int 45 | coin = dice 2 46 | 47 | -- Estas funciones pueden ser llamadas con la mónada estado, dada una 48 | -- semilla inicial, devuelven el resultado y la nueva semilla: 49 | -- 50 | -- λ> runState (dice 6) 1 51 | -- (2,16807) 52 | -- λ> runState (dice 6) 16807 53 | -- (2,282475249) 54 | -- 55 | -- El usar composición con mónadas nos ahorraba controlar los errores 56 | -- en el primer caso, aquí nos ahorra controlar el cambio de semilla, 57 | -- por ejemplo: para lanzar dos dados y hacer que la semilla se pase 58 | -- internamente. 59 | twodices' :: Distribution Int 60 | twodices' = do 61 | a <- dice 6 62 | b <- dice 6 63 | return (a+b) 64 | 65 | (⊕) :: Distribution Int -> Distribution Int -> Distribution Int 66 | (⊕) = liftM2 (+) 67 | (⊗) :: Distribution Int -> Distribution Int -> Distribution Int 68 | (⊗) = liftM2 (*) 69 | 70 | twodices :: Distribution Int 71 | twodices = dice 6 ⊕ dice 6 72 | 73 | -- Igual que hago esto, podría hacer: 74 | -- 75 | -- foldr (⊕) (return 0) [dice 6,dice 6,dice 6] 76 | -- foldr (⊕) (return 0) (replicate 10 (dice 6)) 77 | -- 78 | -- Que da un resultado que se aproxima a una distribución normal. 79 | 80 | -- Ahora, desde ella, podemos crear otras distribuciones. La distribución de 81 | -- bernoulli sería la de una moneda trucada donde una cara tiene probabilidad 82 | -- p y la otra tiene probabilidad (1-p). 83 | bernoulli :: Double -> Distribution Int 84 | bernoulli p = do 85 | sample <- dice 1000000 86 | if (fromIntegral sample / 1000000.0 < p) 87 | then return 1 88 | else return 0 89 | 90 | -- La distribución binomial es la suma de k distribuciones de Bernoulli 91 | binomial :: Int -> Double -> Distribution Int 92 | binomial k p = sum <$> replicateM k (bernoulli p) 93 | 94 | -- La distribución constante y otra forma de escribir la distribución 95 | -- binomial, de manera algebraica. 96 | constant :: Int -> Distribution Int 97 | constant n = return n 98 | 99 | binomial' :: Int -> Double -> Distribution Int 100 | binomial' k p = foldr (⊕) (constant 0) (replicate k (bernoulli p)) 101 | 102 | 103 | 104 | 105 | -- Muestra la distribución. Los detalles de implementación no son interesantes. 106 | -- Hemos usado TypeSynonymInstances para simplificar el proceso de sobrecargar 107 | -- la instancia de Show y poder dibujar directamente por la pantalla las 108 | -- demostraciones. 109 | instance Show (State Seed Int) where 110 | show = showdist 111 | 112 | showdist :: Distribution Int -> String 113 | showdist dist = unlines $ map counter [minimum samples..maximum samples] 114 | where samples = fst $ runState (replicateM 50000 dist) 1 115 | counter n = show n <> ":\t " <> replicate ((count n samples) `div` (3000 `div` range)) '#' 116 | range = maximum samples - minimum samples + 1 117 | 118 | count :: Eq a => a -> [a] -> Int 119 | count x = length . filter (x==) 120 | 121 | 122 | main :: IO () 123 | main = return () 124 | -------------------------------------------------------------------------------- /SegundaParte/4.parsers.hs: -------------------------------------------------------------------------------- 1 | -- Calcula la tabla de multiplicación de un grupo 2 | -- usando el Algoritmo de Knuth-Bendix. 3 | -- 4 | -- Usa HaskellForMaths, que puede instalarse como: 5 | -- cabal install HaskellForMaths 6 | import Math.Algebra.Group.StringRewriting 7 | import Text.ParserCombinators.Parsec 8 | import Data.List hiding (group) 9 | 10 | 11 | -- Definiciones de tipos. 12 | -- * Un generador es un caracter. 'a' 13 | -- * Una expresión es una cadena de generadores. 'aab' 14 | -- * Una relación es un par de expresiones. 'ab = ba' 15 | -- * Una tabla de multiplicación es una tabla de expresiones. 16 | -- * Un grupo está definido por sus generadores y sus relaciones. 17 | type Gen = Char 18 | type Exp = [Gen] 19 | type Rel = (Exp,Exp) 20 | newtype Table = Table [[Exp]] 21 | 22 | data Group = Group [Gen] [Rel] 23 | deriving (Show) 24 | 25 | -- Enseñamos cómo debe mostrar por pantalla las tablas de multiplicación 26 | -- y las expresiones. ¡La lista vacía de elementos será la identidad del grupo! 27 | instance Show Table where 28 | show (Table table) = intercalate "\n" $ fmap (intercalate "\t" . (fmap showexp)) table 29 | 30 | showexp :: Exp -> String 31 | showexp "" = "1" 32 | showexp ex = ex 33 | 34 | 35 | 36 | 37 | -- Calcula la tabla de multiplicación del grupo, 38 | -- dados sus generadores y sus relaciones. 39 | multtable :: Group -> Table 40 | multtable (Group gens rels) = Table [[rewrite cs (a <> b) | a <- nf] | b <- nf] 41 | where cs = knuthBendix rels 42 | nf = nfs (gens, cs) 43 | 44 | 45 | 46 | -- ¡Parsers! 47 | -- Vamos a usar parsers monádicos. Estos envuelven el resultado 48 | -- dentro de una mónada, y así podemos trabajar con el como si ya lo 49 | -- tuviéramos. Parser a, intenta parsear algo de tipo a. 50 | -- La mónada nos permite componer Parsers. 51 | -- 52 | -- Nuestra idea final es la de parsear la presentación de un grupo: 53 | -- < x,y,z | xy = z; xx = 1; yy = 1; zz = 1 > 54 | -- 55 | 56 | -- Un generador es una letra. 57 | -- Usamos un parser ya construído. 58 | generator :: Parser Gen 59 | generator = letter 60 | 61 | -- La identidad la parseamos aparte, pero es también una 62 | -- expresión. Leemos el caracter 1, pero lo que queremos 63 | -- devolver es la lista vacía, porque ("aa","") representará 64 | -- que "aa" puede sustituirse por el vacío, o la identidad. 65 | identity :: Parser Exp 66 | identity = char '1' >> return "" 67 | 68 | -- Una lista de generadores la forman generadores separados 69 | -- por comas: x,y,z 70 | -- 71 | -- sepBy toma dos parsers y devuelve varias instancias del 72 | -- primero separadas por el segundo. 73 | generatorList :: Parser [Gen] 74 | generatorList = generator `sepBy` (char ',') 75 | 76 | -- Una expresión la forman varios generadores, literalmente, 77 | -- o quizás es sólo un 1, identidad del grupo 78 | expression :: Parser Exp 79 | expression = try identity <|> many generator 80 | 81 | -- Para leer una relación ab = ba debo leer la primera parte, un 82 | -- igual, y la segunda parte. 83 | relation :: Parser Rel 84 | relation = do 85 | lefthand <- expression 86 | char '=' 87 | righthand <- expression 88 | return (lefthand, righthand) 89 | 90 | -- Lee un grupo finitamente generado como: 91 | -- < a,b | ab = ba > 92 | group :: Parser Group 93 | group = do 94 | char '<' 95 | genList <- generatorList 96 | char '|' 97 | relations <- relation `sepBy` (char ';') 98 | char '>' 99 | return (Group genList relations) 100 | 101 | 102 | 103 | -- Lee desde la entrada estándar, filtrando los espacios 104 | -- devuelve la tabla de multiplicación del grupo 105 | main :: IO () 106 | main = do 107 | solv <- fmap multtable <$> (parse group "") <$> filteredinput 108 | putStrLn $ either (const "Error") show solv 109 | where 110 | filteredinput :: IO String 111 | filteredinput = filter (/= ' ') <$> getLine 112 | 113 | 114 | {- 115 | 116 | Ejemplos de uso. 117 | 118 | Grupo de Klein. Z/2Z x Z/2Z 119 | < a,b | aa = 1; bb = 1; ab = ba > 120 | 1 a b ab 121 | a 1 ab b 122 | b ab 1 a 123 | ab b a 1 124 | 125 | Grupo diédrico de orden 3. D3 126 | < s,t | ss=1; ttt=1; ts=stt > 127 | 1 s t st ts tt 128 | s 1 ts tt t st 129 | t st tt ts s 1 130 | st t s 1 tt ts 131 | ts tt st t 1 s 132 | tt ts 1 s st t 133 | 134 | -} 135 | -------------------------------------------------------------------------------- /apuntes/introHaskell.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libreim/haskell/ebe17a649bd50ee69340f2de803086fe32cd6f5d/apuntes/introHaskell.pdf -------------------------------------------------------------------------------- /apuntes/introHaskell.tex: -------------------------------------------------------------------------------- 1 | %%% 2 | % Apuntes para un seminario de introducción a Haskell 3 | % Author: Pablo Baeyens 4 | % Author: Mario Román 5 | % 6 | % License: 7 | % CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/) 8 | %%% 9 | 10 | %%% 11 | % Este archivo parte de una modificación de una plantilla de Latex para 12 | % adaptarla al castellano. 13 | % Su autor original es Frits Wenneker (http://www.howtotex.com). 14 | %%% 15 | 16 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17 | % Short Sectioned Assignment 18 | % LaTeX Template 19 | % Version 1.0 (5/5/12) 20 | % 21 | % This template has been downloaded from: 22 | % http://www.LaTeXTemplates.com 23 | % 24 | % Original author: 25 | % Frits Wenneker (http://www.howtotex.com) 26 | % 27 | % License: 28 | % CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/) 29 | % 30 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 31 | 32 | %------------------------------------------------------------------------------- 33 | % PAQUETES 34 | %------------------------------------------------------------------------------- 35 | 36 | \documentclass[paper=a4, fontsize=11pt, spanish]{tufte-handout} 37 | \usepackage[T1]{fontenc} 38 | \usepackage[utf8]{inputenc} 39 | \usepackage[spanish]{babel} 40 | \selectlanguage{spanish} 41 | 42 | \usepackage{xcolor} % Colores 43 | \usepackage{amsmath} % align* 44 | \usepackage{ulem} % Enlaces 45 | \usepackage{listings} % Código 46 | 47 | \usepackage{environ} 48 | \usepackage{tikz} 49 | \usetikzlibrary{babel} 50 | \usetikzlibrary{matrix, shapes, decorations, positioning} 51 | 52 | \setlength{\parskip}{1.2ex} 53 | \setlength{\parindent}{0pt} 54 | 55 | %------------------------------------------------------------------------------- 56 | % TITULO Y FORMATO GENERAL 57 | %------------------------------------------------------------------------------- 58 | 59 | \title{Introducción a Haskell} 60 | \renewcommand{\and}{\hspace*{1cm}} % tufte-handout no define \and :( 61 | \author{Mario Román \and Pablo Baeyens} % Your name 62 | \date{\textbf{v1.1} - Febrero 2019} 63 | 64 | %% Enlaces %% 65 | \newcommand{\enlace}[2]{\href{#1}{\dotuline{#2}}} 66 | 67 | %% Otros comandos %% 68 | \newcommand{\seccion}[1]{\input{./sections/#1.tex}} % Incluir secciones 69 | \newcommand{\espacio}{\vspace*{\baselineskip}} % Añade espacios 70 | \newcommand{\R}{\mathbb{R}} 71 | 72 | %------------------------------------------------------------------------------- 73 | % ENTORNOS 74 | %------------------------------------------------------------------------------- 75 | 76 | %% CÓDIGO %% 77 | 78 | % Colores 79 | \definecolor{backg}{HTML}{F2F2F2} % Fondo 80 | \definecolor{comments}{HTML}{BDBDBD} % Comentarios 81 | \definecolor{keywords}{HTML}{08388c} % Palabras clave 82 | \definecolor{strings}{HTML}{0489B1} % Strings 83 | 84 | \lstset{ 85 | language=haskell, 86 | basicstyle=\small\ttfamily, 87 | breaklines=true, 88 | backgroundcolor=\color{backg}, 89 | keywordstyle=\color{keywords}, 90 | commentstyle=\color{comments}, 91 | stringstyle=\color{strings}, 92 | morekeywords={Tree}, 93 | tabsize=2, 94 | % Acentos, ñ, ¿, ¡ (tex.stackexchange.com/questions/24528) 95 | extendedchars=true, 96 | literate={á}{{\'a}}1 {é}{{\'e}}1 {í}{{\'i}}1 {ó}{{\'o}}1 97 | {ú}{{\'u}}1 {ñ}{{\~n}}1 {¡}{{\textexclamdown}}1 98 | {¿}{{?`}}1 {->}{{$\rightarrow$}}1 {=>}{{$\Rightarrow$}}1 {\\}{{$\lambda$}}1 99 | } 100 | 101 | 102 | %% ENTORNOS LATERALES %% 103 | 104 | \definecolor{extra}{HTML}{005190} % Color base para bloques extra 105 | \definecolor{otro}{HTML}{8d0033} % Color base para otros 106 | 107 | \NewEnviron{extra}[1]{% 108 | \begin{marginfigure} 109 | \setlength{\parskip}{1.2ex} 110 | \begin{tikzpicture} 111 | \node [inner sep=10pt, inner ysep=15pt, fill=extra!10] (box){% 112 | \begin{minipage}{\textwidth} 113 | \noindent\BODY 114 | \end{minipage} 115 | }; 116 | 117 | \node[right=0cm of box.north west, fill=extra, 118 | text=white, text width=5.57cm, text height=0.3cm] (m) 119 | {\smallcaps{#1}}; 120 | \end{tikzpicture} 121 | \end{marginfigure} 122 | } 123 | 124 | \NewEnviron{otro}[1]{% 125 | \begin{marginfigure} 126 | \setlength{\parskip}{1.2ex} 127 | \begin{tikzpicture} 128 | \node [inner sep=10pt, inner ysep=15pt, fill=otro!10] (box){% 129 | \begin{minipage}{\textwidth} 130 | \noindent\BODY 131 | \end{minipage} 132 | }; 133 | 134 | \node[right=0cm of box.north west, fill=otro, 135 | text=white, text width=5.57cm, text height=0.3cm] (m) 136 | {\smallcaps{#1}}; 137 | \end{tikzpicture} 138 | \end{marginfigure} 139 | } 140 | 141 | %------------------------------------------------------------------------------- 142 | % DOCUMENTO 143 | %------------------------------------------------------------------------------- 144 | 145 | 146 | \begin{document} 147 | 148 | \maketitle 149 | 150 | \seccion{ghc} 151 | \seccion{tipos} 152 | \seccion{constr} 153 | \seccion{funciones} 154 | \seccion{defTipos} 155 | \newpage 156 | \seccion{apendice} 157 | 158 | \end{document} 159 | -------------------------------------------------------------------------------- /apuntes/sections/apendice.tex: -------------------------------------------------------------------------------- 1 | \appendix 2 | 3 | \section{Apéndice} 4 | 5 | En este apéndice se incluyen otros temas de interés sobre la sintaxis o uso de 6 | Haskell. 7 | 8 | \subsection{Comprensión de listas} 9 | 10 | La comprensión de listas es una forma de escribir listas parecida a la notación para 11 | expresar conjuntos por extensión. Su sintaxis es: 12 | \begin{lstlisting} 13 | -- [ | <- , ] 14 | [x*2 | x <- [1..10]] -- [2,4,6,8,10,12,14,16,18,20] 15 | [x*2 | x <- [1..10], x*2 >= 12] -- [12,14,16,18,20] 16 | \end{lstlisting} 17 | 18 | Cada elemento de la lista es sustituido en la expresión, que puede depender de la variable, y, si 19 | cumple los predicados se añadirá a la lista. Si se utilizan varios predicados éstos se separan por 20 | comas. También podemos utilizar varias listas, cada una ligada a una variable. En este caso las 21 | variables se sustituirán por cada combinación posible de los elementos: 22 | \begin{lstlisting} 23 | [ (x,y) | x <- [1,2,3], y <- [8,3], x < y] 24 | -- [(1,8),(1,3),(2,8),(2,3),(3,8)] 25 | \end{lstlisting} 26 | 27 | \section{Listas infinitas y evaluación perezosa} 28 | La sintaxis de rangos nos permite escribir listas infinitas: 29 | 30 | \begin{fullwidth} 31 | \begin{lstlisting} 32 | [1..] -- Enteros positivos 33 | fibs = 0 : 1 : zipWith (+) fibs (tail fibs) -- Secuencia de Fibonacci 34 | repeat :: a -> [a] -- Crea listas infinitas con todos los elementos iguales 35 | repeat n = n : repeat n -- repeat n = [n,n..] 36 | \end{lstlisting} 37 | \end{fullwidth} 38 | 39 | Si intentamos mostrar estas listas en el intérprete no acabará. Sin embargo, podemos utilizarlas 40 | junto con otras funciones sin problema: 41 | 42 | \begin{fullwidth} 43 | \begin{lstlisting} 44 | zip [1..] ["azul","verde","rojo"] -- [(1,"azul"),(2,"verde"),(3,"rojo")] 45 | \end{lstlisting} 46 | \end{fullwidth} 47 | 48 | Esto sucede porque Haskell es un lenguaje de evaluación no estricta o perezoso, por lo que sólo evaluará 49 | los elementos que necesite. Así, en \texttt{||}, el segundo elemento sólo se evaluará si el 50 | primero es \texttt{False}, ya que si es \texttt{True} el valor de la expresión ya estará fijado. 51 | 52 | 53 | \subsection{Prueba del compilador de Haskell} 54 | 55 | Escribimos el clásico programa \textit{"Hello World"} para Haskell, 56 | que servirá para probar el compilador. 57 | En \texttt{test.hs} escribimos el programa: 58 | 59 | \begin{lstlisting} 60 | main = putStrLn "Hello World!" 61 | \end{lstlisting} 62 | 63 | Compilamos usando \texttt{ghc -o hello test.hs}. 64 | Acabamos de definir la función \texttt{main} como la función \texttt{putStrLn} 65 | aplicada sobre la cadena \texttt{``Hello World!''}. 66 | 67 | A diferencia de lo que haríamos en un lenguaje imperativo no le decimos que 68 | para ejecutar \texttt{main} haya que ejecutar una función \texttt{putStr}, 69 | sino que \textbf{definimos} \texttt{main} como la función. 70 | 71 | Además del compilador, \textit{Haskell Platform} incluye \texttt{runghc}, un 72 | intérprete no interactivo que podríamos llamar con \texttt{runghc test.hs} 73 | para este ejemplo. 74 | 75 | \subsection{Ejemplos prácticos y más} 76 | 77 | En la carpeta \texttt{examples} hay algunos ejemplos prácticos de programas 78 | completos. Si quieres seguir aprendiendo, recomendamos los siguientes recursos: 79 | 80 | \begin{itemize} 81 | \item \enlace{http://stackoverflow.com/questions/1012573}{Getting started with Haskell} 82 | \item \enlace{http://tryhaskell.org/}{Try Haskell} 83 | \item \enlace{http://aprendehaskell.es/}{¡Aprende Haskell por el bien de todos!} 84 | \item \enlace{https://en.wikibooks.org/wiki/Haskell}{Wikibooks - Haskell} 85 | \item \enlace{https://wiki.haskell.org/Learning_Haskell}{Learning Haskell} 86 | \item \enlace{http://book.realworldhaskell.org/}{Real World Haskell} 87 | \end{itemize} 88 | -------------------------------------------------------------------------------- /apuntes/sections/constr.tex: -------------------------------------------------------------------------------- 1 | \section{Constructores de tipos} 2 | 3 | Dados los tipos básicos podemos combinarlos para construir nuevos tipos en otras 4 | estructuras como listas, árboles o tuplas. Podemos pensar en los constructores de 5 | tipos como funciones sobre tipos: Toman uno o más tipos y devuelven un nuevo tipo. 6 | 7 | \begin{extra}{Sinonimos de tipo} 8 | \texttt{String} es un sinónimo de tipo de \texttt{[Char]}: 9 | son distintos nombres para el mismo tipo. La notación usual para 10 | cadenas es equivalente a la de listas: 11 | 12 | \espacio 13 | 14 | \texttt{"hi" == ['h','i']} 15 | 16 | \espacio 17 | 18 | Los sinónimos de tipo se definen con la palabra clave \texttt{type}: 19 | 20 | \espacio 21 | 22 | \texttt{type String = [Char]} 23 | \end{extra} 24 | 25 | Veamos algunos ejemplos: 26 | 27 | \subsection{Listas} 28 | Las listas almacenan colecciones ordenadas de valores de un tipo homogéneo. 29 | Su tamaño \textbf{no es fijo}, es decir, listas de distintos tamaños pertenecen 30 | al mismo tipo. 31 | 32 | Una lista se escribe entre corchetes, separando sus elementos por comas. 33 | La lista vacía se escribe \texttt{[]}: 34 | 35 | \begin{lstlisting} 36 | [1,2,3] :: [Int] 37 | [] :: [a] 38 | ['a','b'] :: [Char] 39 | \end{lstlisting} 40 | 41 | También podemos utilizar el constructor \texttt{:}, 42 | que antepone un elemento al principio de una lista: 43 | \begin{lstlisting} 44 | [1,2,3] == 1:2:3:[] 45 | \end{lstlisting} 46 | 47 | \begin{extra}{Rangos} 48 | Haskell proporciona una sintaxis de rangos para tipos enumerables, que permite 49 | definir listas fácilmente. Prueba estos ejemplos: 50 | 51 | \begin{itemize} 52 | \item \texttt{[1..10]} 53 | \item \texttt{['a'..'m']} 54 | \item \texttt{[1,4..20]} 55 | \item \texttt{[10,8..1]} 56 | \end{itemize} 57 | 58 | Su implementación se basa en la clase de tipos \texttt{Enum}. 59 | \end{extra} 60 | 61 | Algunas funciones relevantes sobre listas (y otras estructuras \footnote{\texttt{null}, \texttt{elem} y \texttt{length} funcionan sobre otro tipo de estructuras de datos como conjuntos, árboles o vectores en versiones recientes de GHC. \texttt{<>} funciona sobre cualquier semigrupo.}) son: 62 | 63 | \begin{itemize} 64 | \item \texttt{<> :: [a] -> [a] -> [a]}: concatena dos listas. 65 | \item \texttt{head :: [a] -> a}: devuelve la cabeza (primer elemento). 66 | \item \texttt{tail :: [a] -> [a]}: devuelve la cola. 67 | \item \texttt{null :: [a] -> Bool}: indica si una lista está vacía. 68 | \item \texttt{elem :: Eq a => a -> [a] -> Bool}: indica si un elemento está en la lista. 69 | \item \texttt{(!!) :: [a] -> Int -> a}: elemento en la posición dada. 70 | \item \texttt{length :: [a] -> Int}: 71 | \footnote{La mayoría de funciones sobre listas están restringidas sobre \texttt{Int} 72 | por razones de retrocompatibilidad.} indica la longitud. 73 | \end{itemize} 74 | 75 | Otras funciones generalizan una función binaria sobre una lista u otras estructuras. Es el caso de 76 | \texttt{sum}, \texttt{product}, \texttt{maximum} o \texttt{minimum}. 77 | 78 | \subsection{Tuplas} 79 | Las tuplas son un tipo que almacena varios datos en una sola estructura. 80 | Podemos pensar en ellas como el producto cartesiano de dos tipos. 81 | 82 | Podemos guardar por ejemplo una película y su año: 83 | 84 | \begin{lstlisting} 85 | (1960, "Psicosis") :: (Int, String) 86 | \end{lstlisting} 87 | 88 | Las tuplas tienen un tamaño \textit{fijo}. Cada n-tupla es un tipo diferente. 89 | Pueden contener elementos de distintos tipos. 90 | 91 | Es usual utilizar los pares (2-tuplas), como en la función \texttt{zip}. 92 | Esta función toma dos listas y devuelve una lista de pares con los elementos de 93 | cada lista: 94 | 95 | \begin{lstlisting} 96 | zip :: [a] -> [b] -> [(a,b)] 97 | \end{lstlisting} 98 | 99 | No existen tuplas de un elemento, aunque sí existe la tupla vacía, escrita \texttt{()} 100 | y llamada \textit{unit}, que funciona como \texttt{None} en Python o \texttt{void} en C++. 101 | -------------------------------------------------------------------------------- /apuntes/sections/defTipos.tex: -------------------------------------------------------------------------------- 1 | \subsection{Definición de tipos} 2 | Para definir un tipo utilizamos \texttt{data}. \footnote{Existen otras formas 3 | de definir tipos. Puedes leer más 4 | \enlace{https://en.wikibooks.org/wiki/Yet_Another_Haskell_Tutorial/Type_advanced\#Newtypes}{aquí.}} 5 | Por ejemplo, el tipo \texttt{Bool} se define: 6 | 7 | \begin{lstlisting} 8 | data Bool = False | True 9 | \end{lstlisting} 10 | 11 | Después de \texttt{data} indicamos el nombre del tipo y después de \texttt{=} indicamos los 12 | \textit{constructores de datos}, separados por \texttt{|}. Tanto el nombre de tipo como 13 | los constructores de datos deben empezar con mayúscula. \footnote{Excepto si son un 14 | símbolo como en los tipos numéricos o en las listas.} Podemos pensar en un tipo como 15 | \texttt{Int} como si estuviera definido: 16 | 17 | \begin{fullwidth} 18 | \begin{lstlisting} 19 | data Int = -9223372036854775808 | ... | -1 | 0 | 1 | ... | 9223372036854775807 20 | \end{lstlisting} 21 | \end{fullwidth} 22 | 23 | Podemos definir tipos con campos que dependan de otros tipos, como por ejemplo 24 | puntos en el espacio: 25 | 26 | \begin{lstlisting} 27 | data Point = Point Int Int Int 28 | \end{lstlisting} 29 | 30 | Como vemos un tipo puede llamarse igual que uno de sus constructores y 31 | para indicar un campo de un cierto tipo ponemos el tipo en el lugar del campo. 32 | Los tipos pueden definirse recursivamente, como en el caso de los naturales 33 | según los axiomas de Peano: 34 | 35 | \begin{lstlisting} 36 | data Nat = Zero | Succ Nat 37 | \end{lstlisting} 38 | 39 | Un natural puede ser el cero o un sucesor de un natural. 40 | 41 | También podemos definir \textbf{constructores de tipos}. Podemos verlos como 42 | funciones sobre tipos: toman como argumento uno o más tipos y definen nuevos 43 | tipos. Es el caso del tipo lista o de las tuplas 44 | \footnote{Las definiciones de listas y tuplas son primitivas para poder usar 45 | esta notación. Podríamos definir tipos equivalentes utilizando sintaxis legal.}: 46 | 47 | \begin{lstlisting} 48 | data [a] = [] | a : [a] 49 | data (a,b) = (a,b) 50 | \end{lstlisting} 51 | 52 | Después del nombre del constructor de tipos damos un nombre a las variables que 53 | utiliza (\texttt{a}). Podemos ver entonces que \texttt{[a]} puede 54 | ser una lista vacía (\texttt{[]}) o un par de elementos, el primero de tipo 55 | \texttt{a} y el segundo una lista de tipo \texttt{a}. 56 | 57 | Los constructores de datos se utilizan para definir funciones en lo que se conoce 58 | como \textit{reconocimiento de patrones}. Cuando definimos una función podemos 59 | emplear una variable para un argumento o bien un constructor de datos. 60 | Por ejemplo\footnote{Podemos usar el mismo nombre para las variables de tipo y 61 | los nombres de los elementos del constructor porque sus ámbitos son distintos.}: 62 | 63 | \begin{lstlisting} 64 | fst :: (a,b) -> a 65 | fst (a,b) = a 66 | \end{lstlisting} 67 | 68 | Como vimos antes en el caso de las listas es habitual utilizar el constructor 69 | \texttt{:} 70 | \footnote{Debemos poner \texttt{head (x:xs)} y no \texttt{head x:xs} ya que si 71 | no nuestra función estaría tomando 3 argumentos: \texttt{x}, \texttt{:} y \texttt{xs} 72 | }: 73 | 74 | \begin{lstlisting} 75 | head (x:xs) = x 76 | second (x:y:xs) = y 77 | \end{lstlisting} 78 | 79 | Otro ejemplo es \texttt{(<>)}\footnote{En realidad, esta definición debería estar dentro de una instancia de \texttt{Semigroup}}: 80 | \begin{lstlisting} 81 | (<>) :: [a] -> [a] -> [a] 82 | [] <> ys = ys 83 | (x:xs) <> ys = x : (xs <> ys) 84 | \end{lstlisting} 85 | 86 | Podemos utilizar el reconocimiento de patrones sobre cualquier tipo que soporte 87 | la igualdad utilizando cualquier constructor del tipo. Debemos asegurarnos de que 88 | cubrimos todos los constructores. 89 | -------------------------------------------------------------------------------- /apuntes/sections/funciones.tex: -------------------------------------------------------------------------------- 1 | \section{Recursividad} 2 | 3 | La recursividad es la base de Haskell. Como Haskell comprueba en el orden de 4 | definición, el caso base debe escribirse antes para que se llegue a ejecutar: 5 | 6 | \begin{lstlisting} 7 | factorial 0 = 1 8 | factorial n = n * factorial (n-1) 9 | \end{lstlisting} 10 | 11 | En una función con más de un argumento debemos definir casos base para todos los 12 | argumentos\footnote{En realidad este ejemplo puede hacerse con sólo dos casos (!)}: 13 | 14 | \begin{lstlisting} 15 | zip :: [a] -> [b] -> [(a,b)] 16 | zip [] _ = [] 17 | zip _ [] = [] 18 | zip (a:as) (b:bs) = (a,b) : zip as bs 19 | \end{lstlisting} 20 | 21 | En la mayoría de los casos puede probarse por inducción que la función termina 22 | en casos finitos\footnote{En otros lenguajes como \enlace{https://www.idris-lang.org/}{Idris}, basado en Haskell, esta demostración puede hacerse por el compilador de forma automática en algunos casos}. En las \textbf{listas} el caso base suele ser la lista vacía\footnote{Esta no es una implementación eficiente de la función longitud (¿puedes ver por qué?) pero la presentamos así por sencillez}: 23 | 24 | \begin{lstlisting} 25 | length :: [a] -> Int 26 | length [] = 0 27 | length (_:xs) = 1 + length xs 28 | \end{lstlisting} 29 | 30 | También puede no haber caso base: 31 | 32 | \begin{lstlisting} 33 | repeat :: a -> [a] 34 | repeat a = a : repeat a 35 | \end{lstlisting} 36 | 37 | \section{Funciones de orden superior} 38 | Las funciones de orden superior son aquellas que toman funciones como parámetros. 39 | Esto permite modularizar el código. El objetivo es tener funciones simples 40 | que se compongan para formar las funciones más complejas: 41 | 42 | Tomemos estas dos funciones: 43 | 44 | \begin{lstlisting} 45 | mult 1 x = x 46 | mult n x = x + (mult (n-1) x) 47 | 48 | replica 1 s = s 49 | replica n s = s <> (replica (n-1) s) 50 | \end{lstlisting} 51 | 52 | Tienen un patrón común: Aplican una misma función binaria un cierto número de 53 | veces. Por tanto podríamos definir: 54 | 55 | \begin{lstlisting} 56 | repite :: (a -> a -> a) -> Int -> a -> a 57 | repite f 1 x = x 58 | repite f n x = f x (repite f (n-1) x) 59 | \end{lstlisting} 60 | 61 | De esta forma: 62 | \texttt{mult = repite (+)} y \texttt{replica = repite (<>)}. 63 | Esto nos deja unas funciones mucho más limpias y más fáciles de mantener. 64 | 65 | \begin{extra}{Funciones lambda} 66 | Las funciones lambda son funciones anónimas. Por ejemplo: 67 | 68 | \espacio 69 | 70 | \texttt{\textbackslash x $\to$ x + 4} 71 | 72 | \espacio 73 | 74 | Son útiles para ser pasadas como argumento cuando son suficientemente simples. 75 | Pueden tomar varios argumentos, que quedan currificados: 76 | 77 | \espacio 78 | 79 | \texttt{\textbackslash x y $\to$ x * (y + 2)} 80 | 81 | \end{extra} 82 | 83 | Otro ejemplo sería construir una función que aplique otra 2 veces: 84 | 85 | \begin{lstlisting} 86 | applyTwice :: (a -> a) -> a -> a 87 | applyTwice f = f . f 88 | \end{lstlisting} 89 | 90 | \section{Funciones de orden superior sobre listas} 91 | Las listas son muy importantes en Haskell, y para tratarlas existen varias 92 | funciones de orden superior muy utilizadas. Todas estas funciones pueden 93 | generalizarse sobre otros tipos por lo que es importante saber utilizarlas: 94 | 95 | \texttt{map} toma una función y una lista y la devuelve con la función aplicada 96 | a sus elementos. Su definición es: 97 | \begin{lstlisting} 98 | map :: (a -> b) -> [a] -> [b] 99 | map _ [] = [] 100 | map f (x:xs) = f x : map f xs 101 | \end{lstlisting} 102 | 103 | Algunos ejemplos de uso: 104 | \begin{lstlisting} 105 | map (<>"!") ["Sugar", "Spice", "Everything nice"] 106 | map (map (*3)) [[1,2],[5,2,7],[]] 107 | \end{lstlisting} 108 | 109 | \texttt{filter} toma un predicado y una lista, y devuelve una lista con los elementos 110 | que cumplen el predicado: 111 | \begin{lstlisting} 112 | filter :: (a -> Bool) -> [a] -> [a] 113 | filter _ [] = [] 114 | filter p (x:xs) = 115 | if p x 116 | then x : filter p xs 117 | else filter p xs 118 | \end{lstlisting} 119 | 120 | Un ejemplo es: 121 | 122 | \begin{lstlisting} 123 | filter (`elem` ['0'..'9']) "The answer is 42" 124 | \end{lstlisting} 125 | 126 | \texttt{foldr} 127 | \footnote{Es similar a \texttt{reduce} en Python. o \texttt{accumulate} en C++. 128 | Existe otra función \texttt{foldl} que aplica los paréntesis de izquierda a derecha.} 129 | toma una función binaria ($\oplus$) y un valor por defecto ($z$) y 130 | aplican la función a los elementos de una lista ordenadamente: 131 | 132 | \begin{equation*} 133 | \operatorname{foldr} \; [a_1 , a_2 , \dots , a_n] = 134 | a_1 \oplus (a_2 \oplus (\dots \oplus (a_n \oplus z ))) 135 | \end{equation*} 136 | 137 | Su definición es\footnote{Como pasaba cuando presentamos las funciones sobre listas esta función puede generalizarse a otras estructuras en las que tendrá una definición diferente}: 138 | 139 | \begin{lstlisting} 140 | foldr :: (a -> b -> b) -> b -> [a] -> b 141 | foldr f z [] = z 142 | foldr f z (x:xs) = f x (foldr f z xs) 143 | \end{lstlisting} 144 | 145 | Estas funciones tienen un gran poder expresivo. Si queremos obtener la suma 146 | o el producto de los elementos de una lista podemos hacerlo con \texttt{foldr}: 147 | 148 | \begin{lstlisting} 149 | sum = foldr (+) 0 150 | product = foldr (*) 1 151 | concat = foldr (<>) [] 152 | \end{lstlisting} 153 | 154 | Con \texttt{foldr} podemos definir \texttt{map}, \texttt{filter} y la mayoría de 155 | funciones sobre listas. 156 | -------------------------------------------------------------------------------- /apuntes/sections/ghc.tex: -------------------------------------------------------------------------------- 1 | \section {El compilador y el intérprete} 2 | 3 | \begin{otro}{Instalación de GHC} 4 | \enlace{https://www.haskell.org/platform/}{Haskell Platform} 5 | contiene un compilador, depurador, gestor de librerías y otras utilidades 6 | para programar en Haskell. 7 | 8 | Puede instalarse desde su página oficial o desde los 9 | repositorios de la mayoría de distribuciones GNU/Linux 10 | (\texttt{haskell-platform}). 11 | \end{otro} 12 | 13 | \texttt{ghc} es el compilador más utilizado para Haskell. Contiene además gran cantidad 14 | de extensiones no estándar del lenguaje. En este documento asumimos la versión GHC 8 o superior. 15 | \footnote{En caso de que utilices una versión anterior de GHC debes utilizar el operador \texttt{++} en lugar del operador \texttt{<>}.} 16 | 17 | \texttt{ghci} es el intérprete interactivo asociado a \texttt{ghc}. 18 | Para simplificar el proceso de E/S en esta introducción usaremos el intérprete 19 | para cargar un archivo \footnote{Puedes probarlo online en \enlace{https://repl.it/languages/haskell}{repl.it}.} 20 | y trabajaremos los archivos desde el propio intérprete. 21 | El intérprete permite los siguientes comandos: 22 | 23 | \begin{itemize} 24 | \item \texttt{:q \phantom{modulo}} \qquad Salir 25 | \item \texttt{:l modulo} \qquad Cargar \texttt{modulo} 26 | \item \texttt{:r \phantom{modulo}} \qquad Recargar módulos 27 | \item \texttt{:t expr\phantom{lo}} \qquad Comprobar tipo de \texttt{expr} \footnote{ 28 | Si queremos que \texttt{ghci} nos muestre el tipo de las expresiones por defecto 29 | podemos usar \texttt{:set +t}.} 30 | \item \texttt{:i \phantom{modulo}} \qquad Obtener información 31 | \end{itemize} 32 | 33 | Una vez instalado \texttt{ghci}, crea un archivo \texttt{archivo.hs} y 34 | cárgalo con \texttt{:l archivo}. 35 | 36 | \section{Conceptos básicos} 37 | 38 | Haskell es un lenguaje de programación funcional puro, perezoso y con tipos fuertes 39 | y estáticos, nombrado en honor a Haskell Curry. 40 | 41 | En Haskell las funciones \textbf{no tienen efectos secundarios}: no alteran el 42 | mundo ni cambian el valor de sus argumentos. No existen las variables: la 43 | ejecución de un programa se basa en evaluar expresiones: sustituir 44 | \enlace{http://stackoverflow.com/questions/210835}{\textit{iguales por iguales}}. 45 | 46 | \begin{otro}{Efectos secundarios} 47 | ¿Podemos optimizar $ f(x) - f(x) \rightarrow 0$? 48 | 49 | \espacio 50 | 51 | En un lenguaje imperativo las funciones pueden tener efectos secundarios: 52 | si su valor de retorno depende del mundo exterior o es aleatorio las expresiones 53 | podrían no ser equivalentes. 54 | 55 | \espacio 56 | 57 | Un lenguaje funcional nos da más libertad: la ausencia de efectos secundarios 58 | permite realizar gran cantidad de optimizaciones y razonamientos. 59 | \end{otro} 60 | 61 | Estas restricciones permiten optimizar enormemente nuestros programas y paralelizar 62 | la evaluación. 63 | 64 | Al no haber efectos secundarios el orden de evaluación no importa permitiendo una 65 | evaluación \textbf{perezosa}, y pudiendo 66 | \enlace{https://libreim.github.io/blog/2015/03/24/algebra-tipos/}{ 67 | razonar algebraicamente} sobre nuestros programas. 68 | 69 | 70 | \section{Llamada a funciones} 71 | 72 | Haskell permite operaciones aritméticas básicas, y operaciones con 73 | cadenas, listas o booleanos. Las siguientes líneas pueden ejecutarse en el 74 | intérprete, devolviendo el resultado esperado: 75 | 76 | \begin{lstlisting} 77 | 5 + 6 * 4 78 | (+) 5 6 79 | "Hello " <> "World!" 80 | True && False 81 | not True 82 | "Hello" == "Hello" 83 | 5 == (+) 2 3 84 | \end{lstlisting} 85 | 86 | Si ejecutamos algo como \texttt{True == 'a'} Haskell nos indicará que los tipos 87 | no concuerdan: 88 | 89 | \begin{lstlisting} 90 | Couldn't match expected type 'Bool' with actual type 'Char' 91 | In the second argument of '(==)', namely ''a'' 92 | In the expression: True == 'a' 93 | \end{lstlisting} 94 | 95 | Las mayoría de las funciones son prefijas. Se escriben dejando sus argumentos a 96 | su lado y separados por espacios. No encerramos los argumentos entre paréntesis 97 | como se haría en la mayoría de lenguajes: 98 | 99 | \begin{lstlisting} 100 | abs 3 -- El valor absoluto de 3 101 | min 28 51 -- El menor entre 28 y 51 102 | negate 2 + 3 -- -2 + 3 103 | negate (2 + 3) -- -(2+3) 104 | (*) (max 6 4) (negate 9) -- Notado como prefijo 105 | id 42 -- Identidad 106 | \end{lstlisting} 107 | 108 | \begin{extra}{Funciones infijas} 109 | Haskell permite escribir funciones infijas como prefijas y viceversa: 110 | 111 | \espacio 112 | 113 | \begin{tabular}{lcl} 114 | \texttt{3 + 4} & $\longleftrightarrow$ & \texttt{(+) 3 4} \\ 115 | \texttt{min 3 2} & $\longleftrightarrow$ & \texttt{3 `min` 2}\\ 116 | \end{tabular} 117 | 118 | \espacio 119 | 120 | Sólo necesitamos añadir paréntesis o acentos graves para convertir 121 | cualquier función de un tipo al otro. 122 | \end{extra} 123 | 124 | Nótese la diferencia entre \texttt{f g 2} y \texttt{f (g 2)}: En el primer caso 125 | llamamos a \texttt{f} con \textbf{2} argumentos (\texttt{g} y \texttt{2}), mientras 126 | que en el segundo la llamamos con uno sólo (\texttt{g 2}). 127 | 128 | Haskell incluye una sentencia condicional \texttt{if}. 129 | \textbf{Siempre} tiene que tener una sentencia \texttt{else}. 130 | Otras estructuras como los bucles no tienen un equivalente directo \footnote{Como aproximación a los bucles tipo «while» y «for» puedes consultar las funciones \texttt{until} de la biblioteca estándar y \texttt{for\_ } del módulo \texttt{Data.Foldable} respectivamente.} en Haskell. 131 | 132 | \begin{lstlisting} 133 | if 3 > 2 then 4 else 3 134 | (if False then "Hello" else "Goodbye") <> " World!" 135 | \end{lstlisting} 136 | 137 | \newpage 138 | -------------------------------------------------------------------------------- /apuntes/sections/listas.tex: -------------------------------------------------------------------------------- 1 | \section{Comprensión de listas y rangos} 2 | \subsection{Rangos} 3 | Los rangos son azúcar sintáctico de listas para crear listas que contengan sucesiones de elementos 4 | de la clase \texttt{Enum}: 5 | 6 | \begin{lstlisting} 7 | [1..10] -- [1,2,3,4,5,6,7,8,9,10] 8 | ['a'..'m'] -- "abcdefghijklm" 9 | [1,4..20] -- [1,4,7,10,13,16,19] 10 | [10,8..1] -- [10,8,6,4,2] 11 | \end{lstlisting} 12 | 13 | Esta clase contiene los objetos que pueden ser enumerados. Puede usarse con \texttt{Double}, pero 14 | no es recomendable por los errores de coma flotante. 15 | 16 | \subsection{Comprensión de listas} 17 | La comprensión de listas es una forma de escribir listas parecida a la notación para 18 | expresar conjuntos por extensión. Su sintaxis es: 19 | \begin{lstlisting} 20 | -- [ | <- , ] 21 | [x*2 | x <- [1..10]] -- [2,4,6,8,10,12,14,16,18,20] 22 | [x*2 | x <- [1..10], x*2 >= 12] -- [12,14,16,18,20] 23 | \end{lstlisting} 24 | 25 | Cada elemento de la lista es sustituido en la expresión, que puede depender de la variable, y, si 26 | cumple los predicados se añadirá a la lista. Si se utilizan varios predicados éstos se separan por 27 | comas. También podemos utilizar varias listas, cada una ligada a una variable. En este caso las 28 | variables se sustituirán por cada combinación posible de los elementos: 29 | \begin{lstlisting} 30 | [ (x,y) | x <- [1,2,3], y <- [8,3], x < y] 31 | -- [(1,8),(1,3),(2,8),(2,3),(3,8)] 32 | \end{lstlisting} 33 | 34 | \section{Listas infinitas y evaluación perezosa} 35 | La sintaxis de rangos nos permite escribir listas infinitas: 36 | 37 | \begin{lstlisting} 38 | [1..] -- Enteros positivos 39 | fibs = 0 : 1 : zipWith (+) fibs (tail fibs) -- Secuencia de Fibonacci 40 | repeat :: a -> [a] -- Crea listas infinitas con todos los elementos iguales 41 | repeat n = n : repeat n -- repeat n = [n,n..] 42 | \end{lstlisting} 43 | 44 | Si intentamos mostrar estas listas en el intérprete no acabará. Sin embargo, podemos utilizarlas 45 | junto con otras funciones sin problema: 46 | 47 | \begin{lstlisting} 48 | zip [1..] ["azul","verde","rojo"] -- [(1,"azul"),(2,"verde"),(3,"rojo")] 49 | \end{lstlisting} 50 | 51 | Esto sucede porque Haskell es un lenguaje de evaluación no estricta o perezoso, por lo que sólo evaluará 52 | los elementos que necesite. Así, en \texttt{||}, el segundo elemento sólo se evaluará si el 53 | primero es \texttt{False}, ya que si es \texttt{True} el valor de la expresión ya estará fijado. 54 | -------------------------------------------------------------------------------- /apuntes/sections/tipos.tex: -------------------------------------------------------------------------------- 1 | \section {El sistema de tipos} 2 | 3 | En Haskell están definidos los tipos básicos comunes a otros lenguajes, 4 | y pueden usarse directamente. 5 | Podemos comprobar el tipo de cualquier expresión con \texttt{:t}. \footnote{ 6 | Algunos de estos ejemplos están simplificados; se describen en la sección de 7 | clases de tipos.} Por ejemplo: 8 | 9 | \begin{lstlisting} 10 | True :: Bool 11 | 'a' :: Char 12 | "a" :: String 13 | 10^320 :: Integer 14 | 2 :: Int 15 | 3.3 :: Double 16 | \end{lstlisting} 17 | 18 | Los tipos de Haskell son \textbf{estáticos} y \textbf{fuertes}. 19 | El compilador hace comprobaciones de tipo e infiere los tipos cuando no se 20 | declaran explícitamente. La mayoría de errores de un código escrito en Haskell 21 | serán de tipos; en otro caso, sólo pueden ser errores de sintaxis o lógicos. 22 | 23 | \begin{otro}{Tipos fuertes y estáticos} 24 | En un sistema de tipos estáticos el tipo de todos los elementos es conocido en tiempo de compilación. 25 | Es el caso de C++, pero no el de Python o Javascript. 26 | 27 | \espacio 28 | 29 | Un sistema de tipos fuertes impide la conversión implícita entre tipos. En C++ 30 | los tipos no son fuertes: podemos convertir un entero a un booleano 31 | de forma implícita para comprobar si es nulo. 32 | \end{otro} 33 | 34 | 35 | \subsection{Polimorfismo} 36 | 37 | Algunos datos pueden tener más de un tipo. En estos casos, Haskell asume 38 | el tipo más general e infiere el tipo concreto al usarlo. 39 | Podemos indicar el tipo de los objetos que usemos para 40 | facilitar la depuración. 41 | 42 | \begin{lstlisting} 43 | fst :: (a,b) -> a 44 | id :: a -> a 45 | \end{lstlisting} 46 | 47 | Sobre enteros la identidad tendría tipo \texttt{id :: Int -> Int}, y sobre 48 | booleanos \texttt{id :: Bool -> Bool}. Haskell infiere el tipo más general: puede 49 | tomar un tipo cualquiera (\texttt{a}) y devuelve un elemento de ese tipo. La letra 50 | \texttt{a} es una \textbf{variable de tipo}. 51 | 52 | \begin{extra}{Variables de tipo} 53 | Las variables de tipo deben empezar con una letra \textbf{minúscula}. 54 | Usualmente se utiliza una sola letra, pero puede 55 | utilizarse cualquier identificador que empiece por minúscula. 56 | 57 | \espacio 58 | 59 | En contraposición, los tipos concretos empiezan por una letra 60 | \textbf{mayúscula} (\texttt{Bool} y no \texttt{bool}). Si los escribimos en 61 | minúscula el compilador pensará que son una variable de tipo. 62 | \end{extra} 63 | 64 | \subsection{Clases de tipos} 65 | 66 | Algunos tipos tienen propiedades comunes. Para aprovecharlas se definen 67 | \textbf{clases de tipos}, que agrupan tipos con la misma interfaz. 68 | La mayoría de los tipos son instancias de \texttt{Eq}, 69 | porque disponen de una función \texttt{(==)} \footnote{Y una función \texttt{(/=)} 70 | para comprobar la desigualdad.}. 71 | Las instancias de la clase \texttt{Num} pueden sumarse y multiplicarse, 72 | las de \texttt{Show} pueden convertirse a texto (\texttt{String}), 73 | y las de \texttt{Integral} permiten calcular restos modulares sobre ellas. 74 | 75 | \newpage 76 | 77 | Las clases de tipos se indican utilizando \texttt{=>}: 78 | 79 | \begin{lstlisting} 80 | 3 :: Num a => a 81 | show :: Show a => a -> String 82 | gcd :: Integral a => a -> a -> a 83 | (==) :: Eq a => a -> a -> Bool 84 | \end{lstlisting} 85 | 86 | Un tipo puede pertenecer a varias clases: \texttt{Integer} pertenece a todas las 87 | clases anteriores. 88 | 89 | \begin{extra}{Tipos numéricos} 90 | Los números en Haskell son polimórficos: \texttt{3} puede ser interpretado como 91 | \texttt{Double} o \texttt{Int}. Esto permite mantener un sistema de tipos fuerte 92 | sin preocuparse por convertirlos explícitamente. 93 | 94 | \espacio 95 | 96 | Los tipos más comúnmente utilizados son: 97 | 98 | \begin{itemize} 99 | \item \texttt{Int}: Enteros de 32 o 64 bits. 100 | \item \texttt{Integer}: Precisión ilimitada. 101 | \item \texttt{Double}: Punto flotante. 102 | \end{itemize} 103 | 104 | \espacio 105 | 106 | Las clases \texttt{Num}, \texttt{Integral} y \texttt{Fractional} unifican ciertas 107 | propiedades de los tipos numéricos. Puedes leer más 108 | \enlace{https://wiki.haskell.org/Converting_numbers}{aquí}. 109 | \end{extra} 110 | 111 | \subsection{Primeras definiciones} 112 | 113 | Todo objeto en Haskell es una función: una constante es simplemente una función 114 | sin argumentos: 115 | 116 | \begin{lstlisting} 117 | constante = 28 118 | \end{lstlisting} 119 | 120 | Definimos las funciones con una serie de igualdades que cubran todas las formas 121 | posibles de los argumentos de entrada. El compilador intentará encajar los 122 | argumentos en alguna de esas formas en orden y usará la \textbf{primera} 123 | definición que encaje. Veamos un ejemplo: 124 | 125 | \begin{lstlisting} 126 | muestra :: Bool -> String 127 | muestra True = "True" 128 | muestra False = "False" 129 | \end{lstlisting} 130 | 131 | \begin{extra}{Librerías} 132 | Cargamos librerías con \texttt{import }, tanto en un archivo como en 133 | \texttt{ghci}. Si no están ya instaladas podemos hacerlo utilizando 134 | \texttt{cabal}. 135 | 136 | \espacio 137 | 138 | Para buscar una función concreta existe \enlace{http://www.haskell.org/hoogle/}{Hoogle}, 139 | que permite buscar una función por nombre o por tipo. 140 | \end{extra} 141 | 142 | Podemos poner opcionalmente antes de la definición el tipo. Esto se llama 143 | \textbf{declaración de tipo}. En la mayoría de las ocasiones Haskell es capaz 144 | de deducir el tipo de una función: 145 | 146 | \begin{lstlisting} 147 | duplica x = x + x 148 | \end{lstlisting} 149 | 150 | Cuando usemos variables estas tienen que empezar por \textbf{minúscula} o ser 151 | \texttt{\_} \footnote{Este es el único nombre de variable que puede utilizarse 152 | más de una vez}, que utilizamos para indicar que el argumento no se va a utilizar: 153 | 154 | \begin{lstlisting} 155 | esNulo :: Int -> Bool 156 | esNulo 0 = True 157 | esNulo _ = False 158 | 159 | esPar x = esNulo (mod x 2) 160 | \end{lstlisting} 161 | 162 | 163 | \subsection {Funciones, tipos y currificación} 164 | Las funciones en un lenguaje funcional son tratadas como objetos 165 | de primera clase. Pueden pasarse como argumentos o ser devueltas como resultado. 166 | Por defecto una función en Haskell es currificada. 167 | 168 | La currificación es la identificación entre las funciones: 169 | \begin{align*} 170 | \begin{matrix} 171 | f: A \times B \to C & \quad & f: A \to (B \to C) \\ 172 | f(a,b) = c & \quad & f(a)(b) = c 173 | \end{matrix} 174 | \end{align*} 175 | 176 | En lugar de tener una función que toma dos argumentos y devuelve 177 | un resultado, tenemos una función que toma un argumento y devuelve otra 178 | función que toma otro argumento para devolver el resultado. 179 | Por ejemplo, la suma queda: 180 | \begin{align*} 181 | \begin{matrix} 182 | (+) :: & \R \times \R & \rightarrow & \R & \quad & (+) :: & \R & \rightarrow & (\R \rightarrow \R) \\ 183 | & x , y & \mapsto & x+y & \quad & & x & \mapsto & (y \mapsto x+y) 184 | \end{matrix} 185 | \end{align*} 186 | 187 | De esta forma una función binaria toma un argumento y devuelve una función 188 | unaria. Por inducción se definen funciones de más argumentos, toman un sólo argumento 189 | y devuelven 190 | \footnote{Consideramos $\rightarrow$ asociativo por la derecha, de tal forma que 191 | \texttt{a -> b -> c} es equivalente a \texttt{a -> (b -> c)}} 192 | una función con un argumento menos: 193 | 194 | \begin{lstlisting} 195 | (&&) :: Bool -> Bool -> Bool 196 | (+) :: Num a => a -> a -> a 197 | const :: a -> b -> a 198 | (==) :: Eq a => a -> a -> Bool 199 | \end{lstlisting} 200 | 201 | Podemos indicar sólo una parte de los argumentos de una función. Esto se conoce 202 | como \textbf{aplicación parcial}. Aquí definimos la función 203 | \texttt{xor} y definimos la negación sobre ella, usando primero la definición 204 | normal y luego usando aplicación parcial: 205 | 206 | \begin{lstlisting} 207 | xor :: Bool -> Bool -> Bool 208 | xor x y = (not x && y) || (x && not y) 209 | 210 | neg' x = xor True x -- Sin aplicación parcial 211 | neg = xor True -- Con aplicación parcial 212 | \end{lstlisting} 213 | 214 | \begin{extra}{Combinando funciones} 215 | Existen 3 operadores muy utilizados para combinar funciones: 216 | 217 | \espacio 218 | 219 | \begin{itemize} 220 | \item \texttt{(f . g) x = f (g x)} 221 | \item \texttt{flip f x y = f y x} 222 | \item \texttt{f \$ x = f x} 223 | \end{itemize} 224 | 225 | \espacio 226 | 227 | \texttt{.} es la composición de funciones y \texttt{flip} cambia el orden de 228 | los argumentos. 229 | 230 | \texttt{\$} es el operador con menor prioridad, lo que permite ahorrar paréntesis: 231 | 232 | \espacio 233 | 234 | \texttt{succ (9 + 10)} $\rightarrow$ \texttt{succ \$ 9 + 10} 235 | 236 | \end{extra} 237 | De la misma forma podemos llamar \texttt{(+)} con sólo un argumento, y nos 238 | devolverá la función que suma ese número: 239 | 240 | \begin{lstlisting} 241 | suma5 = (5+) 242 | mult2 = (2+) 243 | \end{lstlisting} 244 | 245 | Podemos componer funciones con la función composición, \texttt{(.)} y aprovechar 246 | la aplicación parcial para omitir argumentos. 247 | 248 | \begin{lstlisting} 249 | f = suma5 . mult2 -- f x = 2*x + 5 250 | \end{lstlisting} 251 | 252 | \newpage 253 | -------------------------------------------------------------------------------- /ejercicios.md: -------------------------------------------------------------------------------- 1 | 2 | 0. Define las siguientes funciones: 3 | 4 | - `not :: Bool -> Bool` 5 | - `(&&) :: Bool -> Bool -> Bool` 6 | - `max :: Ord a => a -> a -> a` 7 | - `even :: Int -> Bool` 8 | - `head :: [a] -> a` 9 | - `(.) :: (b -> c) -> (a -> b) -> (a -> c)` (composición de funciones) 10 | - `takeWhile :: (a -> Bool) -> [a] -> [a]` 11 | 12 | 1. Define una función para encontrar el último elemento de una lista, y otra para 13 | encontrar el penúltimo. 14 | 15 | 2. Define una función `rango :: Int -> Int -> [Int]` de tal forma que `rango a b` 16 | sea el rango entre a y b. 17 | 18 | 3. Define una función `mcd :: Int -> Int -> Int` que calcule el máximo común divisor 19 | entre dos enteros. 20 | 21 | 4. Define una función que diga si una lista es sublista de otra. 22 | 23 | 5. La función `zip :: [a] -> [b] -> [(a,b)]` crea parejas de las dos listas pasadas 24 | como argumento: 25 | 26 | - Define `zip`. 27 | - ¿Qué hace `zip [0..]`? 28 | - Generalizar la definición a `zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]`, 29 | que empareja los elementos de las listas usando la función pasada 30 | (`zipWith (+) [1,2] [2,3,4] == [1+2, 2+3]`) 31 | - Define `zip` utilizando `zipWith` 32 | 33 | 6. Una sentencia condicional en Haskell se escribe: 34 | ```haskell 35 | if {-cond-} then {-caso de que sí -} else {-caso de que no -} 36 | ``` 37 | Define una función `ifThenElse` que implemente una sentencia condicional. 38 | ¿Cuál es su tipo? 39 | 40 | 7. Define la función `until :: (a -> Bool) -> (a -> a) -> a -> a`, que aplica 41 | una función `(a -> a)` sobre un elemento inicial `a` hasta que no se cumpla un 42 | predicado `(a -> Bool)`. 43 | 44 | 8. La función `$ :: (a -> b) -> a -> b` se define `f $ x = f x`. Es el operador 45 | infijo con menor precedencia, de tal forma que puede utilizarse para evitar 46 | paréntesis. También tiene otros usos: 47 | 48 | - ¿Para qué puede utilizarse `map ($0)`? 49 | - ¿Y `zipWith ($)`? 50 | 51 | 9. Define la función `curry :: ((a, b) -> c) -> a -> b -> c`, que *currifica* una 52 | función de dos argumentos. 53 | 54 | 10. Según los axiomas de Peano, un número natural puede ser 0 o un sucesor de 55 | otro número natural. Define el tipo `Nat` que define los números naturales de 56 | esta manera. Implementa: 57 | 58 | - Las funciones `suma, producto :: Nat -> Nat -> Nat`. 59 | - Las funciones `par, impar :: Nat -> Bool`. 60 | - Una función `toInt :: Nat -> Int` que convierta un natural en un entero. 61 | 62 | 11. Sea `g :: [a] -> b` una función tal que `g [] = v` y `g (x:xs) = f x (g xs)`. 63 | Define `g` utilizando `foldr`. Aplica éste patrón para definir las siguientes 64 | funciones: 65 | 66 | - `concat :: [[a]] -> [a]` 67 | - `maximum :: [a] -> a` 68 | - `length :: Num t => [a] -> t` 69 | - `<> :: [a] -> [a] -> [a]` 70 | - `map :: (a -> b) -> [a] -> [b]` 71 | - `filter :: (a -> Bool) -> [a] -> [a]` 72 | 73 | 12. ¿Cual es el tipo de `(.) . (.)`? ¿Para qué puede utilizarse? 74 | --------------------------------------------------------------------------------