viernes, febrero 27, 2009

Sobre tipos y lenguajes de scripting

me llego un call for papers para este workshop http://www.cs.purdue.edu/homes/wrigstad/stop09/STOP/About.html

y se me ocurrió lo que se puede hacer con lenguajes de scripting para los "locos por los tipos"

acá va el código y después la explicación

ensure.py: provee los decoradores para asegurar tipos en parámetros y valor de retorno
import functools

ensure_types = True

def args_types(*args_types, **kwargs_types):
def wrapper(function):
@functools.wraps(function)
def replacement(*args, **kwargs):
for (count, (arg, arg_type)) in enumerate(zip(args, args_types)):
if type(arg) != arg_type:
raise ValueError('Invalid type for arg ' + str(count) +
' expected ' + str(arg_type) + ' got ' + str(type(arg)))

for name, ktype in kwargs_types.iteritems():
if name in kwargs:
if type(kwargs[name]) != ktype:
raise ValueError('Invalid type for karg "' + name +
'" expected ' + str(ktype) + ' got ' + str(type(kwargs[name])))

return function(*args, **kwargs)

if ensure_types:
replacement._is_wrapped = True
return replacement
else:
function._is_wrapped = False
return function

return wrapper

def return_type(return_type):
def wrapper(function):
@functools.wraps(function)
def replacement(*args, **kwargs):
result = function(*args, **kwargs)

if type(result) != return_type:
raise ValueError('Invalid return type expected ' +
str(return_type) + ' got ' + str(type(result)))

return result

if ensure_types:
replacement._is_wrapped = True
return replacement
else:
function._is_wrapped = False
return function

return wrapper


test_ensure.py: prueba la implementación
import ensure
# if ensure.ensure_types is set to False then the decorators
# return the same functions and don't make the type checking
# that an be done when development finished and you want to
# deliver the code (it remove the checks and make the code faster)
# ensure.ensure_types = False

@ensure.args_types(int, str, bool, float, sure=bool, price=float)

def do_something(number, name, sure=False, price=10.0):

print number, name, sure, price

@ensure.return_type(int)

def return_param(param):
return param

if do_something._is_wrapped:

print 'do_something contains type checks'
else:
print 'do_something doesn\'t contains type checks'

if return_param._is_wrapped:

print 'return_param contains type checks'
else:
print 'return_param doesn\'t contains type checks'

print do_something.__name__

print

do_something(1, "spongebob", True)
do_something(1, "spongebob", sure=False)

do_something(1, "spongebob", sure=False, price=2.0)

# Fail
try:
do_something(False, "spongebob")
except ValueError, error:

print error

try:
do_something(1, 12.3)

except ValueError, error:
print error

try:

do_something(1, "patricio", 10)
except ValueError, error:

print error

try:
do_something(1, "patricio", True, 10)

except ValueError, error:
print error

try:

do_something(1, "patricio", sure=None)
except ValueError, error:

print error

try:
do_something(1, "patricio", sure=True, price=None)

except ValueError, error:
print error

print 'returned', return_param(5)

try:
print 'returned', return_param("hi!")
except ValueError, error:

print error


la salida corriendo con ensure.ensure_types = True es:

do_something contains type checks
return_param contains type checks
do_something

1 spongebob True 10.0
1 spongebob False 10.0
1 spongebob False 2.0
Invalid type for arg 0 expected <type 'int'> got <type 'bool'>
Invalid type for arg 1 expected <type 'str'> got <type 'float'>
Invalid type for arg 2 expected <type 'bool'> got <type 'int'>
Invalid type for arg 3 expected <type 'float'> got <type 'int'>
Invalid type for karg "sure" expected <type 'bool'> got <type 'NoneType'>
Invalid type for karg "price" expected <type 'float'> got <type 'NoneType'>
returned 5
returned Invalid return type expected <type 'int'> got <type 'str'>

la salida corriendo con ensure.ensure_types = False es:

do_something doesn't contains type checks
return_param doesn't contains type checks
do_something

1 spongebob True 10.0
1 spongebob False 10.0
1 spongebob False 2.0
False spongebob False 10.0
1 12.3 False 10.0
1 patricio 10 10.0
1 patricio True 10
1 patricio None 10.0
1 patricio True None
returned 5
returned hi!

Conclusión:

con esta librería se le podría dar a los que lo quieran (no se si yo lo usaría mucho) una forma de checkear en tiempo de ejecución los tipos de datos recibidos como parámetros y los tipos devueltos por las funciones que decidan decorar.
Estas decoraciones sirven también como método para dar hints a los programadores sobre de que tipos son los valores que se reciben en la función y puede ser usado por IDEs para deducir los tipos y mostrar errores/warnings en el cuerpo del código.
Un aspecto positivo es que se puede deshabilitar el decorado seteando ensure.ensure_types = False. En tal caso no se incurre en ningún overhead en tiempo de ejecución, esto podría ser usado luego del ciclo de desarrollo y prueba, donde no se detecto ninguna "violacion de contrato" y se entrega al usuario final el código con los checks en tiempo de ejecución deshabilitados para incrementar la performance de la aplicación.

obviamente se pueden hacer mejoras en el decorador de los parámetros, pero para ser un modulo de 50 lineas y escrito en menos de una hora, esta bastante bien :)

argumentos variables en php

queres tener una funcion con argumentos variables en php?
tenes un array y queres llamar a una funcion con esos argumentos?
'<,'>s/funcion/metodo/g? ;)

entonces este post es para vos!

salio marquerinero el arranque...

bueno ante esas necesidades hice este ejemplito, es un poco tricky pero se puede hacer..

aca va

<?php

function suma($num1, $num2)
{
return $num1 + $num2;
}

function resta($num1, $num2)
{
return $num1 - $num2;
}

function operacion()
{
$args = func_get_args();
$op = array_shift($args);
print($op . '=');
if($op == "suma")
{
print(call_user_func_array('suma', $args));
}
elseif($op == "resta")
{
print(call_user_func_array('resta', $args));
}
else
{
print('?');
}
}

class Foo
{
public function __construct()
{

}

public function suma($num1, $num2)
{
return $num1 + $num2;
}

public static function resta($num1, $num2)
{
return $num1 - $num2;
}
}

$foo = new Foo();

operacion("suma", 2, 2);
operacion("resta", 2, 2);
operacion("asd", 2, 2);
// como llamar a un metodo de un objeto
print('$foo->suma=' . call_user_func_array(array($foo, 'suma'), array(2, 2)));
// como llamar al metodo de una clase
print('Foo::resta=' . call_user_func_array(array('Foo', 'resta'), array(2, 2)));

?>

sábado, febrero 21, 2009

La API de los bancos esta rota

Tengo 3 cheques de pago diferido, lo primero que piensa un ser como yo que nunca en su vida pensó en bancos (y no le interesa pensar en ellos, para eso están, para pensar por nosotros) supongo que si yo los deposito antes ellos se van a tomar el trabajo de guardarlos en algún lugar y el día en el que se deban cobrar los cobran y los depositan en mi cuenta.

Suena normal no? para eso están los bancos, para encargarse de todas esas cosas relacionadas con el dinero que nosotros no queremos saber.

Eso supuse.. resulta que me llega una carta diciendo que no puedo depositar los cheques antes del tiempo del cobro. A mi me pareció la institución mas user-unfriendly del mundo, pero mi viejo que esta acostumbrado a los bancos me dijo "como vas a hacer eso?", lo único que hace es recibir la plata de mi sueldo, ponerla en algún lugar, pagarme un misero interés mucho inferior a la tasa de inflación, usar mi plata para dar créditos (incrementando su valor 9 veces), cobrándome cuando saco plata por el cajero y encima cuando quiero que hagan algo por mi, la primera cosa, no la pueden hacer.

Encima tuve que estar una hora en el banco preguntando haciendo cola y llenando papelitos que supongo que ellos tendrían que llenar (o no tendrían que existir) para que después me digan que mi transacción es invalida 7 días después!.

Encima le dije al cajero, fíjate si esta todo bien porque es la primera ves que deposito un cheque en un banco, miró un poco y me dijo que estaba bien. Ponganle un poco de validación en el front end así no tengo que esperar que mi request llegue al backend para que me lo rebote, eso consume mucho ancho de banda, recursos en el backend y encima me tiene a mi esperando (les suena similar a algo?). Pero desde otro punto de vista hagan una base de datos con cheques en pago diferido depositados antes de fecha y ponganle un cron que todas las mañanas se fije en la fecha de cobro y decida cuales ya se pueden cobrar.

ya casi 150 años tienen estas instituciones y su GUI/API externa/frontend sigue siendo la misma de siempre.

Ahora tengo que ir a buscar los benditos cheques, guardarlos y anotar en algún lado 3 fechas para ir a depositarlos por separado haciendo 3 horas de tramites, llenando 3 papelitos por separado para que ellos tengan la amabilidad de hacerme disponible ese dinero.

viernes, febrero 20, 2009

Sobre los comentarios anonimos y los malentendidos

Mi ultimo post hacia referencia a que porque la proxima release de ubuntu va a empezar con K iba a apestar, si uno piensa un poco puede ver que no tiene sentido racional y que obviamente si leemos el titulo "Flame mode = on" naturalmente es un chiste o algo sin sentido.

Quien asociaría la calidad de una distribución linux en base a la primera letra de la misma?

Parece que alguien si, ya que comento "Guau. Una pelotudez importante." si es una pelotudez, mi blog esta lleno de chistes sin sentido, particularmente ese post, si uno lo seleccionaba podía leer un texto que estaba en blanco que decía PD: todo bien con KDE, es mas un flame a tuza que otra cosa y si incluso no se hubiese leído, era o obra de un troll o una mera asociación tonta de letras. Al no considerarme un troll es obvio que fue meramente un chiste, pero hay gente dispuesta a ser ofendida e interpretar mal cualquier cosa en internet. No se si debería haber posteado esto, ya que me estoy dejando llevar por ellos, pero es solo para aclarar porque ayer me agregaron al planeta de pyar y por ahí no saben que posteo semejantes giladas.

les dejo un chiste alusivo

bienvenidos los de pyar y por favor no se ofendan si algo no me gusta lo fundamento, si sale a modo troll probablemente sea un chiste :)

Flame Mode = On

la proxima version de ubuntu se va a llamar Karmic Koala, si que va a apestar

PD: todo bien con KDE, es mas un flame a tuza que otra cosa ;)

project euler - problema 5

Hasta ahora a todos los problemas los venia resolviendo por fueza bruta aplicando algunas optimizaciones (para que no sea tan bruto vio?), pero decidi ejercitar un poco mis conocimientos matematicos para intentar resolverlo puramente con matematicas o al menos eliminar muchas cosas innecesarias.

el problema 5 es este:

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

What is the smallest number that is evenly divisible by all of the numbers from 1 to 20?

agarre un lapiz y un papel (posta!) y me puse a pensar un poco.

Lo primero que probe (fuerza bruta matematica) es el producto de los numeros del 1 al 20 es divisible por todos ellos, el problema es que no es el mas chico.. entonces pense un poco mas. Porque no es el mas chico? bueno, porque ahi hay muchas multiplicaciones innecesarias, si es multiplo de 20 es tambien multiplo de 10, 5, 4 2 etc.

despues de eso llegue a la conclusion de que el numero era el producto de los numeros del 11 al 20, pero resulto no ser asi, pense un rato mas y no se me ocurrio nada asi que decidi darle mi problema acotado a python, lo que hice a grandes rasgos fue.

incrementar de a 380 el contador (producto de 20 y 19), y ya que incremento en multiplos de 20 y 19 no me hace falta controlar que sean multiplos de ellos, por lo tanto hice una lista de numeros del 18 al 11 ya que los numeros mas chicos se comprueban comprobando esos. Puse los numeros al reves ya que si el numero divisor es mas grande tiene menos numeros multiplos, por lo tanto al cortar al encontrar un numero no divisor en los numeros mas grandes me ahorro algunos calculos innecesarios.

cuando entre a las soluciones vi que la solucion del problema tenia que ver con multiplicar numeros, pero no los numeros en si, sino las potencias mas altas de los primos de la factorizacion del 1 al 20. (aca esta la explicacion http://mathforum.org/library/drmath/view/62527.html)

y bue, tan bueno en la matematica no soy :D

codigo en python

NUMS = [float(x) for x in range(11, 19)]
NUMS.reverse()

def first_multiple_from_1_to_20():
num = 380

while True:
for x in NUMS:
if num % x != 0:
break
else:
return num

num += 380

num = first_multiple_from_1_to_20()

print num


erlang

-module(ej_005).
-export([first_multiple_from_1_to_20/0]).

is_multiple_from_11_to_18(_Value, 10) -> true;
is_multiple_from_11_to_18(Value, Number) ->
case Value rem Number == 0 of
true -> is_multiple_from_11_to_18(Value, Number - 1);
false -> false
end.

is_multiple_from_11_to_18(Value) -> is_multiple_from_11_to_18(Value, 18).

first_multiple_from_1_to_20(Count) ->
case is_multiple_from_11_to_18(Count) of
true -> Count;
false -> first_multiple_from_1_to_20(Count + 380)
end.

first_multiple_from_1_to_20() -> first_multiple_from_1_to_20(380).



lisp

(defun is-multiple-from-11-to-18 (value)
(= (loop for i from 18 downto 11 by 1
while (= (mod value i) 0) finally (return i)) 10))

(defun first-multiple-from-1-to-20 ()
(loop for i from 380 by 380
while (not (is-multiple-from-11-to-18 i))
finally (return i)))

(print (first-multiple-from-1-to-20))

martes, febrero 17, 2009

soy medio idiota

no hace falta ni resaltarle la sintaxis


is_palindrome(Number) ->
String = integer_to_list(Number),
String == lists:reverse(String).

(defun is-palindrome (num)
(setf str (format nil "~a" num))
(equal str (reverse str)))

def is_palindromic(number):
'''return True if the number is a palindrome'''
number = str(number)
return number == number[::-1]


ganas de complicarse...

project euler - problema 4

Ahora que me hice un tiempo encare el cuarto ejercicio, facil, pero me costo sacarme de la cabeza tratar de hacer todo en lisp con recursion y usar el macro loop (que por cierto es el mas poderozo que he visto en cualquier lenguaje).

algunas cosas para observar:

no se si soy yo, pero usar progn y setq en lisp no me convence, siempre pense al principio en hacer todo recursivo y con let, pero parece que se complica a veces (no conozco una forma de evitar los lets nesteados, debe haber una forma pero no la conozco).

en cuanto a erlang no me gusta la diferencia de and andalso y or y orelse, pero parece que esta ahi por razones historicas, el pattern matching es adictivo, no me gusta que no pueda poner ; en el ultimo guard de un case.

hasta ahora vengo resolviendo el problema primero en python, despues en erlang y despues en lisp, por ahi eso condiciona la forma en la que lo resuelvo, pero siempre trato de usar la solucion que mas se adapta al lenguaje.

aca va el codigo

python

def is_palindromic(number):
'''return True if the number is a palindrome'''
number = str(number)

limit_start = len(number) / 2

if len(number) % 2 == 1:
limit_end = limit_start + 1
else:
limit_end = limit_start

return number[limit_start:] == number[:limit_end][::-1]

def get_largest_palindrome():
'''get the largest 3 digit palindrome'''
temp = 0

for i in range(999, 0, -1):
for j in range(i, 0, -1):
value = i * j
if is_palindromic(value):
if temp < value:
temp = value

return temp

print get_largest_palindrome()



lisp

(defun is-palindrome (num)
(progn
(setf str (format nil "~a" num))
(setf size (length str))
(setf first-half (truncate (/ size 2)))
(if (evenp size)
(setf second-half first-half)
; else
(setf second-half (+ first-half 1)))
(equal (subseq str 0 first-half) (reverse (subseq str second-half size)))))

(defun get-largest-palindrome ()
(progn
(setf temp 0)
(loop for i from 999 downto 0 do
(loop for j from i downto 0 do
(progn
(setq value (* i j))
(if (and (is-palindrome value) (> value temp))
(setq temp value)))))
temp))

(print (get-largest-palindrome))



erlang

-module(ej_004).
-compile(export_all).
%-export([get_largest_palindrome/0]).

is_palindrome(Number) ->
String = integer_to_list(Number),
Size = string:len(String),
FirstHalf = Size div 2,

case Size rem 2 == 1 of
false -> SecondHalf = FirstHalf + 1;
true -> SecondHalf = FirstHalf + 2
end,

FirstPart = string:substr(String, 1, FirstHalf),
SecondPart = lists:reverse(string:substr(String, SecondHalf, Size)),

FirstPart == SecondPart.

get_largest_palindrome(0, 0, Accum) -> Accum;
get_largest_palindrome(X, 0, Accum) -> get_largest_palindrome(X - 1, X - 1, Accum);

get_largest_palindrome(X, Y, Accum) ->
Value = X * Y,

case is_palindrome(Value) andalso Value > Accum of
true -> NewValue = Value;
false -> NewValue = Accum
end,

get_largest_palindrome(X, Y - 1, NewValue).

get_largest_palindrome(X, Accum) -> get_largest_palindrome(X, X, Accum).
get_largest_palindrome() -> get_largest_palindrome(999, 0).

miércoles, febrero 11, 2009

project euler - problema 3

problema 3 y observaciones

el operador de modulo en erlang es muy poco intuitivo.

ej

1> 2.0 rem 2.
** exception error: bad argument in an arithmetic expression
in operator rem/2
called as 2.0 rem 2

si salta una excepcion en un guard en erlang no te dice que fue malo solo falla el guard

y alguna cosa mas que no me acuerdo.

python

import math

def factors(value):
factors = []
factor = 2.0
new_value = value
val_sqrt = math.sqrt(value)

while factor < val_sqrt:
if new_value % factor == 0:
factors.append(factor)
#new_value /= factor

factor += 1

return factors

def calculate(value):
return factors(value)[-1]

def print_results():
print calculate(600851475143)

if __name__ == '__main__':
print_results()


erlang

-module(ej_003).
-compile(export_all).

factors(Factor, _Value, Limit, Accum) when Factor > Limit -> lists:reverse(Accum);
factors(Factor, Value, Limit, Accum) when Value rem Factor == 0 ->
factors(Factor + 1, trunc(Value/Factor), Limit, [Factor | Accum]);
factors(Factor, Value, Limit, Accum) ->
factors(Factor + 1, Value, Limit, Accum).

factors(Value) -> factors(2, Value, trunc(math:sqrt(Value)), []).

print_results() ->
Factors = factors(600851475143),
io:format("~w~n", [Factors]),
if
length(Factors) > 0 -> io:format("~w~n", ([lists:last(Factors)]));
true -> io:format("No factor~n")
end.



lisp

(defun factors-helper (value limit)
(loop for factor from 2 when (= (rem value factor) 0) collect factor while (< factor limit)))

(defun factors (value) (factors-helper value (truncate (sqrt value))))

(defun print-results () (print (last (factors 600851475143))))

(print-results)

domingo, febrero 08, 2009

Keep Your Identity Small

http://www.paulgraham.com/identity.html

la conclusión esta buena.

But there is a step beyond thinking of yourself as x but tolerating y: not even to consider yourself an x. The more labels you have for yourself, the dumber they make you.

sábado, febrero 07, 2009

project euler - problema 2

La diferencia es que en python lo hice con generadores ya que queda mas prolijo, hasta donde se no hay generadores en los otros.

Python

# Each new term in the Fibonacci sequence is generated by adding the previous
# two terms. By starting with 1 and 2, the first 10 terms will be:
# 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
# Find the sum of all the even-valued terms in the sequence which do not
# exceed four million.

def fibonacci():
one = 0
two = 1
step = 1

while True:
one, two = two, one + two
yield two
step += 1

def calculate(limit):
result = 0
for value in fibonacci():
if value > limit:
break

if value % 2 == 0:
result += value

return result

def print_result():
print calculate(4000000)

if __name__ == '__main__':
print_result()



Erlang

-module(ej_002).
-compile(export_all).
%-export([calculate/1, print_result/0]).

fibonacci_step(First, Second) -> {Second, First + Second}.

calculate(First, Second, Limit) -> calculate(First, Second, Limit, 0).

calculate(_First, Second, Limit, Accum) when Second > Limit -> Accum;
calculate(First, Second, Limit, Accum) ->
{NewFirst, NewSecond} = fibonacci_step(First, Second),

case NewSecond rem 2 of
0 -> NewAccum = Accum + NewSecond;
1 -> NewAccum = Accum
end,

calculate(NewFirst, NewSecond, Limit, NewAccum).

calculate(Limit) -> calculate(0, 1, Limit).

print_result() -> io:format("~w~n", [calculate(4000000)]).


Lisp (note que los paréntesis dejan de molestar y si lo tabulas de una forma particular se parece mucho a python :D)

(defun fibonacci-step (one two)
(list two (+ one two)))

(defun calculate-helper (one two limit accum)
(cond ((> two limit) accum)
(T (let ((result (fibonacci-step one two)))
(let ((new-one (car result))
(new-two (cadr result)))

(if (eq (rem new-two 2) 0)
(calculate-helper new-one new-two limit (+ accum new-two))
(calculate-helper new-one new-two limit accum)))))))

(defun calculate (limit) (calculate-helper 0 1 limit 0))

(defun print-result () (print (calculate 4000000)))

viernes, febrero 06, 2009

project euler - problema 1

me cree una cuenta en project euler para aprender bien erlang y lisp, voy a intentar resolver todos los problemas en esos lenguajes y en python como lenguaje conocido para comparar los resultados. Obviamente esto es algo que voy a abandonar, la pregunta es cuando :D

No necesariamente voy a usar la misma forma, porque a veces no se puede o no la se, por ahora con tal que ande esta todo bien.

aca va el resultado del primer problema

python

# Add all the natural numbers below one thousand that are multiples of 3 or 5.

# If we list all the natural numbers below 10 that are multiples of 3 or 5,
# we get 3, 5, 6 and 9. The sum of these multiples is 23.
# Find the sum of all the multiples of 3 or 5 below 1000.

def calculate():
return sum(x for x in xrange(1000) if x % 3 == 0 or x % 5 == 0)

def print_result():
print calculate()

if __name__ == '__main__':
print_result()


en erlang

-module(ej_001).
-export([calculate/0, print_result/0]).

calculate() -> lists:sum([X || X <- lists:seq(0, 1000), X rem 3 == 0 orelse X rem 5 == 0]).

print_result() -> io:format("~w~n", [calculate()]).


en lisp

(defun multiple-of-3-or-5 (value)
(or (eq (rem value 3) 0)
(eq (rem value 5) 0))
)

(defun calculate-helper (value accum limit)
(cond ((= value limit)
accum)
((multiple-of-3-or-5 value)
(calculate-helper (+ value 1) (+ accum value) limit))
(T
(calculate-helper (+ value 1) accum limit))
)
)

(defun calculate () (calculate-helper 0 0 1000))

(defun print-result ()
(print (calculate)))

(print-result)

jueves, febrero 05, 2009

Llega un momento en la vida de todo hombre...

en la que uno crea una distribución live basada en ubuntu

mi primer distro live, creada para probar y para ayudar a pyar en su proyecto de difusión del lenguaje, contiene un escritorio liviano (openbox + fbpanel) y un conjunto de herramientas para el desarrollo del lenguaje, entre ellas:

Interpretes
  • python 2.4
  • python 2.5
  • python 3.0
  • ipython
Editores
  • gedit
  • vim
  • emacs
  • scribes
IDEs

  • Geany
  • Glade-3 (no es una ide del todo)
Otros

  • gnome-terminal
  • thunar
  • obconf (para configurar openbox)
  • openbox
  • fbpanel
  • sqlite3
  • NetworkManager
  • firefox
cosas que le faltan

  • agregarle localización a español
  • agregarle una pagina de inicio a firefox con links a la documentación local
  • la documentación local
  • frameworks web
la iso pesa en este momento 387 MB así que hay bastante espacio para seguir poniendo cosas.

como siempre, acá van los screenshots:





recien arrancado


todos los interpretes


todos los editores


geany + documentacion



Thunar, firefox y la configuracion de open box


glade-3

domingo, febrero 01, 2009

Quotes

PHP is a minor evil perpetrated and created by incompetent amateurs, whereas Perl is a great and insidious evil perpetrated by skilled but perverted professionals.

Engineers are all basically high-functioning autistics who have no idea how normal people do stuff.
I invented the term Object-Oriented, and I can tell you I did not have C++ in mind.

he idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying.

Never trust a programmer in a suit.


Seguidores

Archivo del Blog