├── .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 |
--------------------------------------------------------------------------------