0votos

Organizacion pf en Haskell

por josejuan hace 2 años

Realiza la conversión automática desde unas unidades angulares a otras, por lo que pueden usarse funciones que requieren ángulos sin conocer las unidades que precisa el argumento (deduce la conversión el compilador de forma automática).

Programa conversor de angulos. (Python con lenguaje simple)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleInstances, FlexibleContexts, UndecidableInstances, LambdaCase #-} 
import Data.List (intercalate) 
 
-- Lo único que hace falta para admitir conversión automática es definir 
-- cierta conversión, por ejemplo `grados = cv radianes`, de tal forma 
-- que dará igual las unidades que requiera cierta función, que se le 
-- podrá pasar cualquiera de las unidades admitidas en la conversión 
-- 
-- Por ejemplo, si tenemos una función de la forma: 
-- 
--        calcular_algo( cierto_angulo_en_cierta_unidad ) 
-- 
-- Se le podrá llamar con cualquier otra unidad siempre que se use `cv` 
-- 
--        resultado = calcular_algo( cv( angulo_en_CUALQUIER_unidad ) ) 
-- 
-- De forma automática se realizará la conversión que sea necesaria. 
class UnitConversion a b where 
  cv :: a → b 
 
 
 
-- Si por ejemplo alguien define radianes, sólo hay conocimiento de 
-- la conversión entre `Rad` a `Rad`. 
newtype Rad = Rad { rad :: 𝔻 } deriving (Show, Read, Num) 
instance UnitConversion Rad Rad where cv r = r 
 
 
 
-- Ahora, alguien podría añadir otra unidad, en tal caso, tenemos 
-- conocimiento de la conversión a y desde `Rad`. 
-- Por ejemplo con `Gra` (grado centesimal) 
newtype Gra = Gra { gra :: 𝔻 } deriving (Show, Read, Num) 
instance UnitConversion Gra Gra where cv g = g 
instance UnitConversion Rad Gra where cv r = Gra $ 400 × rad r / (2 × π) 
instance UnitConversion Gra Rad where cv g = Rad $ 2 × π × gra g / 400 
 
 
 
-- Lo mismo con `Deg` (grado sexagesimal) 
newtype Deg = Deg { deg :: 𝔻 } deriving (Show, Read, Num) 
instance UnitConversion Deg Deg where cv d = d 
instance UnitConversion Rad Deg where cv r = Deg $ 360 × rad r / (2 × π) 
instance UnitConversion Deg Rad where cv d = Rad $ 2 × π × deg d / 360 
instance UnitConversion Gra Deg where cv g = Deg $ 360 × gra g / 400 
instance UnitConversion Deg Gra where cv d = Gra $ 400 × deg d / 360 
 
 
 
-- Lo mismo con `Rev` (revoluciones) 
newtype Rev = Rev { rev :: 𝔻 } deriving (Show, Read, Num) 
instance UnitConversion Rev Rev where cv i = i 
instance UnitConversion Rad Rev where cv r = Rev $ rad r / (2 × π) 
instance UnitConversion Rev Rad where cv i = Rad $ 2 × π × rev i 
instance UnitConversion Gra Rev where cv g = Rev $ gra g / 400 
instance UnitConversion Rev Gra where cv i = Gra $ 400 × rev i 
instance UnitConversion Deg Rev where cv d = Rev $ deg d / 360 
instance UnitConversion Rev Deg where cv i = Deg $ 360 × rev i 
 
 
 
 
-- Ahora, podemos definir cualquier función que necesite un ángulo 
-- sin importarnos las unidades que usemos (podemos usar cualquiera) 
longitudArco :: 𝔻 → Rad → 𝔻 
longitudArco radio angulo = radio × rad angulo 
 
 
-- Si por ejemplo nos dan otros parámetros en otras unidades, podemos 
-- hacer uso de la función anterior sin saber que dicha función requiere 
-- el ángulo en radianes 
distanciaArcoGradosDecimales :: 𝔻 → Deg → Deg → 𝔻 
distanciaArcoGradosDecimales radio angulo1 angulo2 = longitudArco radio $ cv (angulo2 - angulo1) 
 
 
 
 
 
-- Un posible interface de usuario para realizar las conversiones podría ser 
 
-- Representa un ángulo en alguna unidad 
data TipoA = Radianes | GradosCentesimales | GradosSexagesimales | Revoluciones deriving (Read, Show, Eq, Ord, Enum) 
data Angulo = Angulo { valor :: 𝔻, tipo :: TipoA } 
instance Show Angulo where show (Angulo x u) = show x ⧺ " " ⧺ show u 
instance Read Angulo where readsPrec z s = case words s of 
                                             [x,u] → case (reads x, reads u) of 
                                                       ([(x,[])],[(u,[])]) → [(Angulo x u, [])] 
                                                       _                   → [] 
                                             _     → [] 
 
-- Porqué no, también puede formar parte de `UnitConversion` (como no hay 
-- información de preferencia de almacenamiento en `Angulo` tomamos `Rad` 
-- como el tipo por defecto en que se almacena) 
instance UnitConversion a Rad ⇒ UnitConversion a Angulo where cv a = Angulo (rad $ cv a) Radianes 
instance ( UnitConversion Rad a 
         , UnitConversion Gra a 
         , UnitConversion Deg a 
         , UnitConversion Rev a ) ⇒ UnitConversion Angulo a where cv (Angulo x Radianes           ) = cv $ Rad x 
                                                                  cv (Angulo x GradosCentesimales ) = cv $ Gra x 
                                                                  cv (Angulo x GradosSexagesimales) = cv $ Deg x 
                                                                  cv (Angulo x Revoluciones       ) = cv $ Rev x 
 
 
-- Solicita al usuario un ángulo en algún tipo 
inputAngulo :: IO Angulo 
inputAngulo = do 
  putStrLn ">> Indica un ángulo (ej. \"45 GradosSexagesimal\"):" 
  reads ↥ getLine ↪ λcase 
    [(a,[])] → η a 
    _        → putStrLn ("\t\t·· Escriba un número y luego uno de: " ⧺ intercalate ", " (show ↥ [Radianes … Revoluciones])) » inputAngulo 
 
-- Solicita al usuario un tipo de ángulo 
inputTipoA :: IO TipoA 
inputTipoA = do 
  let opts = zip [1…] [Radianes … Revoluciones] 
  putStrLn ">> Elige un tipo de ángulo:" 
  ↱_(λ(i, t) → putStrLn $ show i ⧺ " - " ⧺ show t) opts 
  reads ↥ getLine ↪ λcase 
    [(i,[])] → case lookup i opts of 
                 𝑁   → putStrLn "\t\t·· Opción incorrecta" » inputTipoA 
                 𝐽 t → η t 
    _        → putStrLn "\t\t··Se esperaba un número de opción" » inputTipoA 
 
-- Interacción 
convertirAngulo :: IO () 
convertirAngulo = do 
  a ← inputAngulo 
  t ← inputTipoA 
  let x = case t of 
            Radianes            → rad $ cv a 
            GradosCentesimales  → gra $ cv a 
            GradosSexagesimales → deg $ cv a 
            Revoluciones        → rev $ cv a 
  putStrLn $ "** Respuesta: " ⧺ show (Angulo x t) 
 
 
 
{- 
 
  Por ejemplo: 
 
 
> forever convertirAngulo 
>> Indica un ángulo (ej. "45 GradosSexagesimal"): 
patata 
    ·· Escriba un número y luego uno de: Radianes, GradosCentesimales, GradosSexagesimales, Revoluciones 
>> Indica un ángulo (ej. "45 GradosSexagesimal"): 
45 GradosSexagesimales 
>> Elige un tipo de ángulo: 
1 - Radianes 
2 - GradosCentesimales 
3 - GradosSexagesimales 
4 - Revoluciones 
** Respuesta: 0.7853981633974483 Radianes 
>> Indica un ángulo (ej. "45 GradosSexagesimal"): 
3 Revoluciones 
>> Elige un tipo de ángulo: 
1 - Radianes 
2 - GradosCentesimales 
3 - GradosSexagesimales 
4 - Revoluciones 
** Respuesta: 18.84955592153876 Radianes 
>> Indica un ángulo (ej. "45 GradosSexagesimal"): 
1 Revoluciones 
>> Elige un tipo de ángulo: 
1 - Radianes 
2 - GradosCentesimales 
3 - GradosSexagesimales 
4 - Revoluciones 
** Respuesta: 6.283185307179586 Radianes 
>> Indica un ángulo (ej. "45 GradosSexagesimal"): 
 
 
-} 

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.