Вам необходимо изменить тип grades
и отказаться от неуместной записи do
; Вы не делаете никаких монадических вычислений. Кроме того, переменные должны начинаться со строчных букв; имена с большой буквы обозначают тип или класс типов.
percentage :: Double -> Double -> Double
percentage a b = a / b
grades :: Double -> Double -> Either String Double
grades x 0 = Left "Zero denominator"
grades x y = let p = percentage x y
in if p > 1 then Left "Greater than 100%"
else Right p
Другой альтернативой является предварительное определение возникающих условий ошибки, а не возврат произвольных строк для их описания; не каждая строка будет описывать одну из двух возможных ошибок, но каждое значение PercentageError
делает.
data PercentageError = ZeroDenominator | Over100Percent
grades :: Double -> Double -> Either PercentageError Double
grades x 0 = Left ZeroDenominator
grades x y = let p = percentage x y
in if p > 1 then Left Over100Percent
else Right p
Мне просто удалось получить ответ самому. Используя библиотеку времени выполнения Obj-C, я получил доступ к свойствам так, как хотел:
- (void)myMethod {
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList([self class], &outCount);
for(i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
const char *propName = property_getName(property);
if(propName) {
const char *propType = getPropertyType(property);
NSString *propertyName = [NSString stringWithCString:propName
encoding:[NSString defaultCStringEncoding]];
NSString *propertyType = [NSString stringWithCString:propType
encoding:[NSString defaultCStringEncoding]];
...
}
}
free(properties);
}
Для этого мне потребовалось создать функцию C 'getPropertyType', который в основном взят из примера кода Apple (прямо сейчас не могу вспомнить точный источник):
static const char *getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T') {
if (strlen(attribute) <= 4) {
break;
}
return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
}
}
return "@";
}
The word "attributes" is a little fuzzy. Do you mean instance variables, properties, methods that look like accessors?
The answer to all three is "yes, but it's not very easy." The Objective-C runtime API includes functions to get the ivar list, method list or property list for a class (e.g., class_copyPropertyList()
), and then a corresponding function for each type to get the name of an item in the list (e.g., property_getName()
).
All in all, it can be kind of a lot of work to get it right, or at least a lot more than most people would want to do for what usually amounts to a really trivial feature.
Alternatively, you could just write a Ruby/Python script that just reads a header file and looks for whatever you'd consider "attributes" for the class.